Beispiel #1
0
        /// <summary>
        /// Stops collector with the given sessionName.
        /// </summary>
        /// <param name="collectorName">
        /// Name of the collector to be stopped.
        /// </param>
        /// <returns>
        /// True if the operation succeeded, false otherwise.
        /// </returns>
        public static bool StopCollector(string collectorName)
        {
            const string MethodName = "StopCollector";

            if (string.IsNullOrEmpty(collectorName))
            {
                throw new ArgumentException("collectorName cannot be null or empty.", "collectorName");
            }

            Logger.Log(
                LoggerLevel.Info,
                LogId,
                MethodName,
                "Attempting to stop ETW session [{0}]",
                collectorName);
            if (!EtwSessionManager.Stop(collectorName))
            {
                Logger.Log(
                    LoggerLevel.Error,
                    LogId,
                    MethodName,
                    "Failed to stop ETW session [{0}]",
                    collectorName);
                return(false);
            }

            Logger.Log(
                LoggerLevel.Info,
                LogId,
                MethodName,
                "ETW session [{0}] was stopped",
                collectorName);

            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// Checks if an existing ETW session satisfies the given collector configuration.
        /// </summary>
        /// <param name="config">
        /// Configuration that should be checked against the existing ETW session.
        /// </param>
        /// <returns>
        /// True if the existing session satisfies the given configuration, false otherwise.
        /// </returns>
        internal static bool ExistingSessionSatisfiesProviders(CollectorConfiguration config)
        {
            // Ok, the session is already in place, just check the providers
            bool providersOk = false;

            NativeMethods.EventTraceProperties sessionProperties;
            if (EtwSessionManager.TryGetSessionProperties(config.Name, out sessionProperties))
            {
                providersOk = true;

                // Loop over providers and ensure that they are good
                var loggerId = sessionProperties.Wnode.HistoricalContext;
                foreach (var provider in config.Providers)
                {
                    NativeMethods.TraceEnableInfo providerInSession;
                    providersOk = EtwSessionManager.GetProviderInfo(loggerId, provider.Value.Id, out providerInSession) &&
                                  providerInSession.IsEnabled != 0 &&
                                  provider.Value.Level <= (EtwTraceLevel)providerInSession.Level &&
                                  (provider.Value.KeywordsAll | providerInSession.MatchAllKeyword) == provider.Value.KeywordsAll &&
                                  (provider.Value.KeywordsAny & providerInSession.MatchAnyKeyword) == provider.Value.KeywordsAny;

                    if (!providersOk)
                    {
                        // pass the native type to a provider to get a nice string representing the
                        // current settings
                        var providerConfigInSession = new ProviderConfiguration(
                            provider.Value.Id,
                            (EtwTraceLevel)providerInSession.Level,
                            providerInSession.MatchAnyKeyword,
                            providerInSession.MatchAllKeyword);
                        Logger.Log(
                            LoggerLevel.Error,
                            LogId,
                            "ExistingSessionSatisfiesProviders",
                            "Provider configuration [{0}] is not satisfied in ETW session [{1}]. Actual provider settings in session: {2}",
                            provider.Value,
                            config.Name,
                            providerInSession.IsEnabled == 0 ? "provider not enabled" : providerConfigInSession.ToString());
                    }
                }
            }

            return(providersOk);
        }
Beispiel #3
0
        /// <summary>
        /// Starts the collector with the given configuration.
        /// </summary>
        /// <param name="config">
        /// The configuration of the collector to be started.
        /// </param>
        /// <returns>
        /// The complete list with the back log of ETL files associated to the collector from oldest to newest.
        /// </returns>
        public List <string> StartCollector(CollectorConfiguration config)
        {
            const string MethodName = "StartCollector";

            var etlBacklog = new List <string>();

            // If a deprecated session exists try to shut it down
            NativeMethods.EventTraceProperties traceProperties;
            if (!string.IsNullOrEmpty(config.DeprecatedCollector))
            {
                StopCollector(config.DeprecatedCollector);
            }

            var clockType          = config.ClockType == ClockType.Default ? ClockType.Perf : config.ClockType;
            var preExistingSession = false;

            if (EtwSessionManager.TryGetSessionProperties(this.Name, out traceProperties))
            {
                if ((NativeMethods.EtwSessionClockType)clockType == traceProperties.Wnode.ClientContext)
                {
                    // Old session can be re-used.
                    preExistingSession = true;
                }
                else
                {
                    // Old session needs to be stopped. Note that if stop failed there is a follow up check to ensure that
                    // the error was not due to the session being stopped between the checks.
                    if (!StopCollector(this.Name))
                    {
                        Logger.Log(
                            LoggerLevel.Error,
                            LogId,
                            MethodName,
                            "Failed to stop existing trace session [{0}]. Cannot proceed to correctly update session.",
                            this.Name);
                        return(etlBacklog);
                    }
                }
            }

            StringBuilder sb = new StringBuilder(256);

            sb.AppendFormat(
                CultureInfo.InvariantCulture,
                "{0} \"{1}\" -nb {2} {3} -bs {4} -ft {5} -ct {6} -ets ",
                preExistingSession ? "update" : "start",
                config.Name,
                config.MinBufferCount.ToString(CultureInfo.InvariantCulture),
                config.MaxBufferCount.ToString(CultureInfo.InvariantCulture),
                config.BufferSizeKB.ToString(CultureInfo.InvariantCulture),
                config.FlushTimerSec.ToString(CultureInfo.InvariantCulture),
                clockType);

            if (config.SessionType == SessionType.Realtime)
            {
                sb.Append("-rt");
            }
            else
            {
                // Add parameters for proper ETL file rotation
                this.isFileCollector  = true;
                this.maxFileCount     = config.MaxFileCount;
                this.maxFileSizeKB    = config.MaxFileSizeMB * 1024;
                this.maxFileTimeSpan  = config.MaxFileTimeSpan;
                this.etlBaseName      = config.OriginalName;
                this.EtlLogsDirectory = Path.Combine(this.baseEtlLocation, config.OriginalName);

                if (!ProtectedIO(
                        () => Directory.CreateDirectory(this.EtlLogsDirectory),
                        e =>
                {
                    Logger.Log(
                        LoggerLevel.Error,
                        LogId,
                        MethodName,
                        "Failed to create directory [{0}] for collector [{1}]. Exception: {2}",
                        this.EtlLogsDirectory,
                        config.Name,
                        e);
                    Logger.Log(
                        LoggerLevel.Error,
                        LogId,
                        MethodName,
                        "Failed to create or update ETW session [{0}]",
                        config.Name);
                }))
                {
                    return(etlBacklog);
                }

                // Get the full list of available ETL files, it will be trimmed according to success of update command.
                etlBacklog = this.GetExistingEtlFiles();

                this.currentEtlSessionFile = this.GenerateNextSessionFileName();
                sb.AppendFormat(CultureInfo.InvariantCulture, "-mode Sequential -o \"{0}\"", this.currentEtlSessionFile);

                if (config.SessionType == SessionType.FileAndRealtime ||
                    config.SessionType == SessionType.RealtimeAndFile)
                {
                    sb.Append(" -rt");
                }
            }

            var exitCode = RunCommand("logman", sb.ToString());

            this.lastRotationTime = DateTime.UtcNow;
            if (exitCode != ExitCodeSuccess)
            {
                Logger.Log(
                    LoggerLevel.Error,
                    LogId,
                    MethodName,
                    "Logman failed to create or update ETW session [{0}].",
                    config.Name);

                if (preExistingSession)
                {
                    if (config.SessionType != SessionType.Realtime)
                    {
                        if (!EtwSessionManager.TryGetCurrentFileOfSession(config.Name, out this.currentEtlSessionFile))
                        {
                            Logger.Log(
                                LoggerLevel.Error,
                                LogId,
                                MethodName,
                                "Failed to retrieve name of the ETL being used by ETW session [{0}].",
                                config.Name);
                        }

                        if (etlBacklog.Count > 0 &&
                            string.Compare(
                                etlBacklog.Last(), this.currentEtlSessionFile, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            etlBacklog.RemoveAt(etlBacklog.Count - 1);
                            Logger.Log(
                                LoggerLevel.Warning,
                                LogId,
                                MethodName,
                                "Current ETL file removed from backlog list since it is still in use. ETL File [{0}]",
                                this.currentEtlSessionFile);
                        }
                    }

                    Logger.Log(
                        LoggerLevel.Info,
                        LogId,
                        MethodName,
                        "Attempting to mitigate with pre-existing session...");
                    if (!ExistingSessionSatisfiesProviders(config))
                    {
                        Logger.Log(
                            LoggerLevel.Error,
                            LogId,
                            "StartCollector",
                            "Pre-existing session cannot be used since it does not satisfy the config.");
                    }
                    else
                    {
                        Logger.Log(
                            LoggerLevel.Error,
                            LogId,
                            MethodName,
                            "Using pre-existing ETW session since it satisfied the configuration.");
                        exitCode = ExitCodeSuccess;
                    }
                }
            }

            if (exitCode == ExitCodeSuccess || preExistingSession)
            {
                Logger.Log(
                    LoggerLevel.Info,
                    LogId,
                    MethodName,
                    "ETW session is in place call UpdateProviders to enable them.");
            }

            etlBacklog.Sort(StringComparer.OrdinalIgnoreCase);
            return(etlBacklog);
        }