public ImmutableProductConfiguration(IProductConfiguration otherConfig)
        {
            Validate.NotNull(otherConfig, nameof(otherConfig));

            _profilesExport_DefaultInterval = otherConfig.ProfilesExport_DefaultInterval;
            _profilesExport_EarlyTriggerOnCollectedStackSnapshotsBytes = otherConfig.ProfilesExport_EarlyTriggerOnCollectedStackSnapshotsBytes;
            _profilesExport_EarlyTriggerOnCollectedStackSnapshotsCount = otherConfig.ProfilesExport_EarlyTriggerOnCollectedStackSnapshotsCount;

            _profilesExport_LocalFiles_Directory = otherConfig.ProfilesExport_LocalFiles_Directory;

            _profilesIngestionEndpoint_Url           = otherConfig.ProfilesIngestionEndpoint_Url;
            _profilesIngestionEndpoint_Host          = otherConfig.ProfilesIngestionEndpoint_Host;
            _profilesIngestionEndpoint_Port          = otherConfig.ProfilesIngestionEndpoint_Port;
            _profilesIngestionEndpoint_ApiPath       = otherConfig.ProfilesIngestionEndpoint_ApiPath;
            _profilesIngestionEndpoint_DatadogApiKey = otherConfig.ProfilesIngestionEndpoint_DatadogApiKey;

            _ddDataTags_Host       = otherConfig.DDDataTags_Host;
            _ddDataTags_Service    = otherConfig.DDDataTags_Service;
            _ddDataTags_Env        = otherConfig.DDDataTags_Env;
            _ddDataTags_Version    = otherConfig.DDDataTags_Version;
            _ddDataTags_CustomTags = otherConfig.DDDataTags_CustomTags;

            _log_IsDebugEnabled            = otherConfig.Log_IsDebugEnabled;
            _log_PreferredLogFileDirectory = otherConfig.Log_PreferredLogFileDirectory;

            _metrics_Operational_IsEnabled = otherConfig.Metrics_Operational_IsEnabled;

            _metrics_StatsdAgent_Port = otherConfig.Metrics_StatsdAgent_Port;

            _frameKinds_Native_IsEnabled = otherConfig.FrameKinds_Native_IsEnabled;
        }
#pragma warning disable CS0162 // Unreachable code detected: Purposeful control using const bool fields in this class.
        public static void SetupLogger(IProductConfiguration config)
        {
            // In case that we are re-initializing, dispose previous log sinks (one log sink via one-or-more redirections).
            DisposeLogSinks();

            if (UseConsoleLogInsteadOfFileLog)
            {
                if (TrySetupConsoleLogger())
                {
                    return;
                }
            }
            else
            {
                if (TrySetupFileLogger(config))
                {
                    return;
                }
            }

            if (UseConsoleLogIfFileLogNotAvailable)
            {
                if (TrySetupConsoleLogger())
                {
                    return;
                }
            }

            ConsoleWriteLine();
            ConsoleWriteLine("PROBLEM! Could not setup logger.");
        }
        public LocalFilesProfilesExporter(IProductConfiguration config)
        {
            _appName = GetSanitizedAppName(config);

            _outputDirectory = GetOutputDirectory(config, _appName);

            _isEnabled = _outputDirectory != null;

            Log.Info(LogSource.Info, "Initialized", "IsEnabled", _isEnabled, "AppName", _appName, "OutputDirectory", _outputDirectory);
        }
Ejemplo n.º 4
0
 public static IProductConfiguration CreateImmutableSnapshot(this IProductConfiguration config)
 {
     if (config == null)
     {
         return(null);
     }
     else
     {
         return(new ImmutableProductConfiguration(config));
     }
 }
Ejemplo n.º 5
0
        public static bool TryCreateAndStart(out ProfilerEngine runningProfilerEngine)
        {
            IProductConfiguration config = ProductConfigurationProvider.CreateDefault()
                                           // .ApplyReleaseDefaults()
                                           // .ApplyDevDefaults()
                                           .ApplyReleaseOrDevDefaults()
                                           .ApplyEnvironmentVariables()
                                           .CreateImmutableSnapshot();

            return(TryCreateAndStart(config, out runningProfilerEngine));
        }
        private static string GetSanitizedAppName(IProductConfiguration config)
        {
            string unsanitizedAppName = config.DDDataTags_Service;

            if (string.IsNullOrWhiteSpace(unsanitizedAppName))
            {
                try
                {
                    unsanitizedAppName = CurrentProcess.GetName();
                }
                catch
                {
                    unsanitizedAppName = "UnknownApp";
                }
            }

            // Sanitize app name:

            var appName = new StringBuilder(unsanitizedAppName);

            // Note that the 'appName' is likely to be based on the service name tag setting, which, in turn,
            // is likely to be based on the ASP.NET site name.
            // Common "unwished" characters that come up in site names, such as '/', '\\', ':' and others are
            // contained in the invalid chars arrays below, especially in 'invalidFilenameChars'.
            char[] invalidPathChars     = Path.GetInvalidPathChars();
            char[] invalidFilenameChars = Path.GetInvalidFileNameChars();

            for (int p = 0; p < appName.Length; p++)
            {
                char c         = appName[p];
                bool isInvalid = char.IsWhiteSpace(c) || c == '.';

                for (int i = 0; i < invalidPathChars.Length && !isInvalid; i++)
                {
                    isInvalid = (c == invalidPathChars[i]);
                }

                for (int i = 0; i < invalidFilenameChars.Length && !isInvalid; i++)
                {
                    isInvalid = (c == invalidFilenameChars[i]);
                }

                if (isInvalid)
                {
                    appName[p] = '_';
                }
            }

            return(appName.ToString());
        }
Ejemplo n.º 7
0
        public MetricsSender(IProductConfiguration config)
        {
            var tags = $"profiler_version:{config.DDDataTags_Version},service_name:{config.DDDataTags_Service},environment:{config.DDDataTags_Env}";

            _tagsAsBytes = Encoding.UTF8.GetBytes(tags);

            _colonAsBytes = Encoding.UTF8.GetBytes(":");
            _metricTypeAndTagsSeparatorAsBytes = Encoding.UTF8.GetBytes("|c|#");

            _socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
            // We consider the statsd agent to be installed locally (for now)
            _statsdAgentEndpoint = CreateEndpoint("127.0.0.1", config.Metrics_StatsdAgent_Port);
            _buffer = new byte[1024];
            _additionalTagsBuilder = new StringBuilder();
        }
Ejemplo n.º 8
0
        public static IProductConfiguration ApplyReleaseOrDevDefaults(this IProductConfiguration config)
        {
            const string EnvVarName = "DD_INTERNAL_USE_DEVELOPMENT_CONFIGURATION";
            const bool   ddInternalUseDevelopmentConfigurationValDefault = false;

            string ddInternalUseDevelopmentConfiguration = Environment.GetEnvironmentVariable(EnvVarName);

            if (
                ConfigurationProviderUtils.TryParseBooleanSettingStr(
                    ddInternalUseDevelopmentConfiguration,
                    ddInternalUseDevelopmentConfigurationValDefault,
                    out bool ddInternalUseDevelopmentConfigurationVal))
            {
                Log.Info(
                    LogComponentMoniker,
                    "Use-Dev-Config environment setting found and parsed.",
                    "Env var name",
                    EnvVarName,
                    "Parsed value",
                    ddInternalUseDevelopmentConfigurationVal);
            }
            else
            {
                Log.Info(
                    LogComponentMoniker,
                    "Use-Dev-Config environment setting not found or not parsed. Default will be used.",
                    "Env var name",
                    EnvVarName,
                    "Value",
                    ddInternalUseDevelopmentConfiguration,
                    "Used default value",
                    ddInternalUseDevelopmentConfigurationVal);
            }

            if (ddInternalUseDevelopmentConfigurationVal)
            {
                return(DevProductConfigurationProvider.ApplyDevDefaults(config));
            }
            else
            {
                return(DefaultReleaseProductConfigurationProvider.ApplyReleaseDefaults(config));
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Called internally AFTER <c>s_singletonAccessLock</c> has been taken and it was validated that no other engine is running.
        /// </summary>
        private static void CreateAndStart(IProductConfiguration config, out ProfilerEngine newProfilerEngine)
        {
            LogConfigurator.SetupLogger(config);
            Log.Info(Log.WithCallInfo(LogSourceMoniker), "Initializing. Will create and start the managed profiler engine.");

            try
            {
                ThreadUtil.EnsureSetCurrentManagedThreadNameNativeCallbackInitialized();

                _currentEngine    = new ProfilerEngine(config);
                newProfilerEngine = _currentEngine;

                LogInitializationCompleted(newProfilerEngine);
            }
            catch (Exception ex)
            {
                Log.Error(Log.WithCallInfo(LogSourceMoniker), "Initialization error.", ex);
                newProfilerEngine = null;
            }
        }
        private string GetOutputDirectory(IProductConfiguration config, string appName)
        {
            if (string.IsNullOrWhiteSpace(config.ProfilesExport_LocalFiles_Directory))
            {
                return(null);
            }

            string outDir;

            // First, try with the defined directory
            try
            {
                if (BuildAndValidateOutputDirectory(config.ProfilesExport_LocalFiles_Directory, appName, isLastResort: false, out outDir))
                {
                    return(outDir);
                }
            }
            catch (Exception ex)
            {
                // Probably did not have permissions to GetCurrentDirectory.
                Log.Error(LogSource.Info.WithCallInfo(), ex);
            }

            // Otherwise, save them in a temp folder
            try
            {
                string tempDir    = Path.GetTempPath();
                string outBaseDir = Path.Combine(tempDir, DirectoryFallbackRoot, DirectoryFallbackSub);
                if (BuildAndValidateOutputDirectory(outBaseDir, appName, isLastResort: true, out outDir))
                {
                    return(outDir);
                }
            }
            catch (Exception ex)
            {
                // Probably did not have permissions to GetTempPath.
                Log.Error(LogSource.Info.WithCallInfo(), ex);
            }

            return(null);
        }
Ejemplo n.º 11
0
        private ProfilerEngine(IProductConfiguration config)
        {
            Validate.NotNull(config, nameof(config));

            _versionInfo = ProfilerEngineVersionInfo.CreateNewInstance();

            _profiledThreadInfoProvider = new ProfiledThreadInfoProvider();
            _profiledAppDomainProvider  = new ProfiledAppDomainProvider();

            _enqueueStackSnapshotBufferSegmentForExport = NativeCallback_EnqueueStackSnapshotBufferSegmentForExport;
            _tryShutdownCurrentManagedProfilerEngine    = NativeCallback_TryShutdownCurrentManagedProfilerEngine;

            _completedStackSnapshots = new StackSnapshotsBufferSegmentCollection();

            _pprofBuilder = new PProfBuilder();

            RegisterReversePInvokeCallbacks();

            _resolveAndExportStacksBackgroundLoop = new ResolveAndExportStacksBackgroundLoop(this, config);
            _resolveAndExportStacksBackgroundLoop.Start();
        }
Ejemplo n.º 12
0
        public static bool TryCreateAndStart(IProductConfiguration config, out ProfilerEngine runningProfilerEngine)
        {
            Validate.NotNull(config, nameof(config));

            runningProfilerEngine = _currentEngine;
            if (runningProfilerEngine != null)
            {
                return(false);
            }

            lock (_singletonAccessLock)
            {
                runningProfilerEngine = _currentEngine;
                if (runningProfilerEngine != null)
                {
                    return(false);
                }

                CreateAndStart(config, out runningProfilerEngine);
                return(runningProfilerEngine != null);
            }
        }
        private static bool TrySetupFileLogger(IProductConfiguration config)
        {
            try
            {
                var filenameBaseInfo = new DatadogEnvironmentFileLogSinkFactory.FilenameBaseInfo(ProductFamily, Product, ComponentGroup);
                if (DatadogEnvironmentFileLogSinkFactory.TryCreateNewFileLogSink(
                        filenameBaseInfo,
                        LoggingDemoLogGroupId,
                        config?.Log_PreferredLogFileDirectory,
                        LogFileSizeBytes,
                        FileFormatOptions,
                        out FileLogSink fileLogSink))
                {
                    RedirectLogs(fileLogSink, out _logRedirections);

                    if (config != null)
                    {
                        LogComposer.IsDebugLoggingEnabled = config.Log_IsDebugEnabled;
                    }
                    else
                    {
                        LogComposer.SetDebugLoggingEnabledBasedOnEnvironment();
                    }

                    return(true);
                }
            }
            catch (Exception ex)
            {
                ConsoleWriteLine();
                ConsoleWriteLine("Error setting up a file logger.");
                ConsoleWriteLine($"{ex}");
            }

            return(false);
        }
Ejemplo n.º 14
0
        public static IProductConfiguration ApplyEnvironmentVariables(this IProductConfiguration config)
        {
            if (config == null)
            {
                return(null);
            }

            var mutableConfig = new MutableProductConfiguration(config);

            if (TryGetEnvironmentVariable("SIGNALFX_PROFILING_UPLOAD_PERIOD", out string envProfilesExportDefaultInterval))
            {
                if (int.TryParse(envProfilesExportDefaultInterval, out var profilesExportDefaultInterval))
                {
                    mutableConfig.ProfilesExport_DefaultInterval = TimeSpan.FromSeconds(profilesExportDefaultInterval);
                }
                else
                {
                    Log.Error(
                        Log.WithCallInfo(LogComponentMoniker),
                        "The environment variable \"SIGNALFX_PROFILING_UPLOAD_PERIOD\" is specified (\"",
                        envProfilesExportDefaultInterval,
                        "\") but cannot be parsed as an int. Using original value: ",
                        mutableConfig.ProfilesExport_DefaultInterval);
                }
            }

            if (TryGetEnvironmentVariable("SIGNALFX_PROFILING_OUTPUT_DIR", out string directory))
            {
                mutableConfig.ProfilesExport_LocalFiles_Directory = directory;
            }

            // If Ingestion Endpoint Url is specified, the Host, Port and ApiPath are ignored.
            // However, that logic is inside the export loop that actually interprets those values.
            // At this point we just extract all of the info that is contained in the environment variables.
            // If both, URL and Host-Port-Etc are specified, we will extract them all and leave the
            // priorization logic of what to use to the config consumer.
            if (TryGetEnvironmentVariable("SIGNALFX_TRACE_AGENT_URL", out string ddTraceAgentUrl))
            {
                mutableConfig.ProfilesIngestionEndpoint_Url = ddTraceAgentUrl;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_AGENT_HOST", out string ddTraceAgentHost))
            {
                mutableConfig.ProfilesIngestionEndpoint_Host = ddTraceAgentHost;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_TRACE_AGENT_PORT", out string szTraceAgentPort))
            {
                if (int.TryParse(szTraceAgentPort, out int port))
                {
                    mutableConfig.ProfilesIngestionEndpoint_Port = port;
                }
                else
                {
                    Log.Error(
                        Log.WithCallInfo(LogComponentMoniker),
                        "The environment variable \"SIGNALFX_TRACE_AGENT_PORT\" is specified (",
                        szTraceAgentPort,
                        ") but cannot be parsed as a number and will be ignored.");
                }
            }

            // Api Key is not required for agent-based ingestion scnarios; it IS required for agent-less ingestion.
            if (TryGetEnvironmentVariable("SIGNALFX_API_KEY", out string ddApiKey))
            {
                mutableConfig.ProfilesIngestionEndpoint_DatadogApiKey = ddApiKey;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_HOSTNAME", out string ddHostName))
            {
                mutableConfig.DDDataTags_Host = ddHostName;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_SERVICE", out string ddServiceName))
            {
                mutableConfig.DDDataTags_Service = ddServiceName;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_ENV", out string ddEnvironment))
            {
                mutableConfig.DDDataTags_Env = ddEnvironment;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_VERSION", out string ddServiceVersion))
            {
                mutableConfig.DDDataTags_Version = ddServiceVersion;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_TAGS", out string ddTagsStr))
            {
                mutableConfig.DDDataTags_CustomTags = ParseAndMergeDdTags(mutableConfig.DDDataTags_CustomTags, ddTagsStr);
            }

            if (TryGetEnvironmentVariable("SIGNALFX_TRACE_DEBUG", out string envIsTraceDebugEnabled))
            {
                const bool isTraceDebugEnabled = true;
                if (
                    ConfigurationProviderUtils.TryParseBooleanSettingStr(
                        envIsTraceDebugEnabled,
                        isTraceDebugEnabled,
                        out bool ddIsTraceDebugEnabledVal))
                {
                    mutableConfig.Log_IsDebugEnabled = ddIsTraceDebugEnabledVal;
                }
                else
                {
                    Log.Error(
                        Log.WithCallInfo(LogComponentMoniker),
                        "The environment variable \"SIGNALFX_TRACE_DEBUG\" is specified (",
                        envIsTraceDebugEnabled,
                        $") but cannot be parsed as a boolean. Using {isTraceDebugEnabled.ToString()} as default");

                    mutableConfig.Log_IsDebugEnabled = isTraceDebugEnabled;
                }
            }

            if (TryGetEnvironmentVariable("SIGNALFX_PROFILING_LOG_DIR", out string ddTraceLogDirectory))
            {
                mutableConfig.Log_PreferredLogFileDirectory = ddTraceLogDirectory;
            }

            if (TryGetEnvironmentVariable("SIGNALFX_INTERNAL_OPERATIONAL_METRICS_ENABLED", out string envIsEnabled))
            {
                const bool isOperationalMetricsEnabled = false;
                if (ConfigurationProviderUtils.TryParseBooleanSettingStr(envIsEnabled, isOperationalMetricsEnabled, out bool isEnabled))
                {
                    mutableConfig.Metrics_Operational_IsEnabled = isEnabled;
                }
                else
                {
                    Log.Error(
                        Log.WithCallInfo(LogComponentMoniker),
                        "The environment variable \"SIGNALFX_INTERNAL_OPERATIONAL_METRICS_ENABLED\" is specified (",
                        envIsEnabled,
                        $") but cannot be parsed as a boolean. Using {isOperationalMetricsEnabled.ToString()} as default");

                    mutableConfig.Log_IsDebugEnabled = isOperationalMetricsEnabled;
                }
            }

            if (TryGetEnvironmentVariable("SIGNALFX_PROFILING_FRAMES_NATIVE_ENABLED", out string envFramesNativeIsEnabled))
            {
                const bool isFramesNativeEnabled = false;
                if (ConfigurationProviderUtils.TryParseBooleanSettingStr(envFramesNativeIsEnabled, isFramesNativeEnabled, out bool isEnabled))
                {
                    mutableConfig.FrameKinds_Native_IsEnabled = isEnabled;
                }
                else
                {
                    Log.Error(
                        Log.WithCallInfo(LogComponentMoniker),
                        "The environment variable \"SIGNALFX_PROFILING_FRAMES_NATIVE_ENABLED\" is specified (",
                        envFramesNativeIsEnabled,
                        $") but cannot be parsed as a boolean. Using isFramesNativeEnabled.ToString() as default");

                    mutableConfig.FrameKinds_Native_IsEnabled = isFramesNativeEnabled;
                }
            }

            return(mutableConfig.CreateImmutableSnapshot());
        }
Ejemplo n.º 15
0
        public static IProductConfiguration ApplyDevDefaults(this IProductConfiguration config)
        {
            if (config == null)
            {
                return(null);
            }

            var mutableConfig = new MutableProductConfiguration(config);

            // mutableConfig.ProfilesExport_DefaultInterval = TimeSpan.FromSeconds(20);
            mutableConfig.ProfilesExport_DefaultInterval = TimeSpan.FromSeconds(60);

            // These bytes are counted as encoded in the buffer segment, i.e. each snapshot takes (26 + 9 per frame) bytes (see StackSnapshotResult.h).
            // Snapshots with 100 frames: 1 snapshot uses 926 bytes, 1MB holds 1132 such snapshots.
            // Snapshots with 50 frames:  1 snapshot uses 476 bytes, 1MB holds 2202 such snapshots
            // Snapshots with 35 frames:  1 snapshot uses 341 bytes, 1MB holds 3075 such snapshots.
            //
            // We will not sample 5 threads more often than once every 9 milliseconds.
            // Assuming 50 frames per snapshot on average (based on some ad-hoc tests with Computer01 demo
            // it is a safe upper bound for the average), we don't expect to generate more than ~33,333 (= 5 * 60 * 1000 / 9) snapshots per minute
            // --> which requires 33,333 / 2202 ~= 15 MB.
            // A 50 MB buffer will work for ~3+ minutes
            // 50,000 samples currespond to ~22 MB.
            mutableConfig.ProfilesExport_EarlyTriggerOnCollectedStackSnapshotsBytes = 50 * 1024 * 1024;  // 50 MBytes
            mutableConfig.ProfilesExport_EarlyTriggerOnCollectedStackSnapshotsCount = 50000;

            mutableConfig.ProfilesExport_LocalFiles_Directory = ConfigurationProviderUtils.GetOsSpecificDefaultPProfDirectory();

            // If Ingestion Endpoint Url is specified, the Host, Port and ApiPath are ignored.
            // mutableConfig.ProfilesIngestionEndpoint_Url = "https://intake.profile.datadoghq.com/v1/input";

            // --> to local agent that sends to staging
            // mutableConfig.ProfilesIngestionEndpoint_Host = "127.0.0.1";                       // Local agent (avoids the IPv4 wait that can occur when using "localhost")
            // mutableConfig.ProfilesIngestionEndpoint_Host = "localhost";                    // Local agent
            // mutableConfig.ProfilesIngestionEndpoint_Host = "intake.profile.datadoghq.com"; // Main DD ingestion endpoint for agent-less
            // mutableConfig.ProfilesIngestionEndpoint_Host = "intake.profile.datad0g.com";   // Staging DD ingestion endpoint for agent-less

            mutableConfig.ProfilesIngestionEndpoint_Port = 8126;   // Local agent's default port
            // mutableConfig.ProfilesIngestionEndpoint_Port = 0;   // Value <= 0 will result the defaut port for the protocol being used.

            mutableConfig.ProfilesIngestionEndpoint_ApiPath = "profiling/v1/input";  // Local agent's API path.
            // mutableConfig.ProfilesIngestionEndpoint_ApiPath = "v1/input";         // DD ingestion endpoint's API path (for agent-less scenarios)

            // Api Key is not required for agent-based ingestion scenarios; it IS required for agent-less ingestion.
            // mutableConfig.ProfilesIngestionEndpoint_DatadogApiKey = "xxx";
            // mutableConfig.ProfilesIngestionEndpoint_DatadogApiKey = null;

            // --> to preprod
            mutableConfig.ProfilesIngestionEndpoint_Url           = "https://intake.profile.datadoghq.com/v1/input";
            mutableConfig.ProfilesIngestionEndpoint_DatadogApiKey = string.Empty;

            string ddService = ConfigurationProviderUtils.GetDdServiceFallback();

            mutableConfig.DDDataTags_Host       = ConfigurationProviderUtils.GetMachineName();
            mutableConfig.DDDataTags_Service    = string.IsNullOrWhiteSpace(ddService) ? ".Net-Profiling-TestService01" : ddService;
            mutableConfig.DDDataTags_Env        = "APM-Profiling-Local";
            mutableConfig.DDDataTags_Version    = "Demo-Version-11";
            mutableConfig.DDDataTags_CustomTags = new KeyValuePair <string, string>[]
            {
                new KeyValuePair <string, string>("CustomTag A", string.Empty),
                new KeyValuePair <string, string>(null, "Some Value B"),
                new KeyValuePair <string, string>("CustomTag C", "Some Value C"),
                new KeyValuePair <string, string>("service", "Foo-Bar")
            };

            mutableConfig.Log_IsDebugEnabled            = true;
            mutableConfig.Log_PreferredLogFileDirectory = ConfigurationProviderUtils.GetOsSpecificDefaultLogDirectory();

            mutableConfig.Metrics_Operational_IsEnabled = false;

            mutableConfig.Metrics_StatsdAgent_Port = 8125;

            // For now, the default installation does not collect native frames.
            // The user can, however, enable it using an environment variable (see 'EnvironmentVariablesConfigurationProvider').
            // This should be changed once the UI supports appropriate filtering.
            mutableConfig.FrameKinds_Native_IsEnabled = false;

            return(mutableConfig.CreateImmutableSnapshot());
        }
 public MutableProductConfiguration(IProductConfiguration otherConfig)
     : base(otherConfig)
 {
 }
        public static IProductConfiguration ApplyReleaseDefaults(this IProductConfiguration config)
        {
            if (config == null)
            {
                return(null);
            }

            var mutableConfig = new MutableProductConfiguration(config);

            mutableConfig.ProfilesExport_DefaultInterval = TimeSpan.FromSeconds(60);

            // These bytes are counted as encoded in the buffer segment, i.e. each snapshot takes (26 + 9 per frame) bytes (see StackSnapshotResult.h).
            // Snapshots with 100 frames: 1 snapshot uses 926 bytes, 1MB holds 1132 such snapshots.
            // Snapshots with 50 frames:  1 snapshot uses 476 bytes, 1MB holds 2202 such snapshots
            // Snapshots with 35 frames:  1 snapshot uses 341 bytes, 1MB holds 3075 such snapshots.
            //
            // We will not sample 5 threads more often than once every 9 milliseconds.
            // Assuming 50 frames per snapshot on average (based on some ad-hoc tests with Computer01 demo
            // it is a safe upper bound for the average), we don't expect to generate more than ~33333 (= 5 * 60 * 1000 / 9) snapshots per minute
            // --> which requires 33333 / 2202 ~= 15 MB.
            // A 500 MB buffer will work for ~33 minutes
            // 1,000,000 samples currespond to ~454 MB.
            //
            // Based on the above, we go with the magic numbers that will limit the buffer to 500 MB and 1 Mio samples
            // by triggering the profiles export if those thresholds are met.
            // These are round numbers that will keep the impact on the customer app in check during early beta stages.
            // During the public beta we need to validate these assumptions and see if the numbers need to be tweaked in either direction.
            mutableConfig.ProfilesExport_EarlyTriggerOnCollectedStackSnapshotsBytes = 500 * 1024 * 1024;  // 500 MBytes
            mutableConfig.ProfilesExport_EarlyTriggerOnCollectedStackSnapshotsCount = 1000000;            // 1,000,000 stack samples

            mutableConfig.ProfilesExport_LocalFiles_Directory = null;

            mutableConfig.ProfilesIngestionEndpoint_Url     = null;                   // If Ingestion Endpoint Url is specified, the Host, Port and ApiPath are ignored.
            mutableConfig.ProfilesIngestionEndpoint_Host    = "127.0.0.1";            // Local agent (avoids the IPv4 wait that can occur when using "localhost")
            mutableConfig.ProfilesIngestionEndpoint_Port    = 8126;                   // Local agent's default port
            mutableConfig.ProfilesIngestionEndpoint_ApiPath = "profiling/v1/input";   // Local agent's API path.

            // Api Key is not required for agent-based ingestion scnarios; it IS required for agent-less ingestion.
            mutableConfig.ProfilesIngestionEndpoint_DatadogApiKey = null;

            // For RELEASE, the we use defaults below, and better values need to be created by setting respective environment variables
            // (see the .ApplyEnvironmentVariables() API in EnvironmentVariablesConfigurationProvider).
            string ddService = ConfigurationProviderUtils.GetDdServiceFallback();

            mutableConfig.DDDataTags_Host       = ConfigurationProviderUtils.GetMachineName();
            mutableConfig.DDDataTags_Service    = string.IsNullOrWhiteSpace(ddService) ? "Unspecified-Service" : ddService;
            mutableConfig.DDDataTags_Env        = "Unspecified-Environment";
            mutableConfig.DDDataTags_Version    = "Unspecified-Version";
            mutableConfig.DDDataTags_CustomTags = new KeyValuePair <string, string> [0];

            // When we get to public beta, Debug-Logging should be DISABLED by default.
            // However, while we are still working towards that level of maturity, debug logs are almost always helpful.
            mutableConfig.Log_IsDebugEnabled            = true;
            mutableConfig.Log_PreferredLogFileDirectory = ConfigurationProviderUtils.GetOsSpecificDefaultLogDirectory();

            mutableConfig.Metrics_Operational_IsEnabled = false;

            mutableConfig.Metrics_StatsdAgent_Port = 8125;

            // For now, the default installation does not collect native frames.
            // The user can, however, enable it using an environment variable (see 'EnvironmentVariablesConfigurationProvider').
            // This should be changed once the UI supports appropriate filtering.
            mutableConfig.FrameKinds_Native_IsEnabled = false;

            return(mutableConfig.CreateImmutableSnapshot());
        }