TeamCity.MSBuild.Logger/NodeLogger.cs (202 lines of code) (raw):

namespace TeamCity.MSBuild.Logger { using System; using System.Diagnostics; using System.Threading; using EventHandlers; using JetBrains.Annotations; using Microsoft.Build.Framework; // ReSharper disable once ClassNeverInstantiated.Global // ReSharper disable once ClassWithVirtualMembersNeverInherited.Global internal class NodeLogger : INodeLogger { [NotNull] private readonly Parameters _parameters; [NotNull] private readonly ILoggerContext _context; [NotNull] private readonly IEnvironment _environment; [NotNull] private readonly IDiagnostics _diagnostics; [NotNull] private readonly IEventRegistry _eventRegistry; [NotNull] private readonly IBuildEventHandler<BuildMessageEventArgs> _messageHandler; [NotNull] private readonly IBuildEventHandler<BuildFinishedEventArgs> _buildFinishedHandler; [NotNull] private readonly IBuildEventHandler<ProjectStartedEventArgs> _projectStartedHandler; [NotNull] private readonly IBuildEventHandler<ProjectFinishedEventArgs> _projectFinishedHandler; [NotNull] private readonly IBuildEventHandler<TargetStartedEventArgs> _targetStartedHandler; [NotNull] private readonly IBuildEventHandler<TargetFinishedEventArgs> _targetFinishedHandler; [NotNull] private readonly IBuildEventHandler<TaskStartedEventArgs> _taskStartedHandler; [NotNull] private readonly IBuildEventHandler<TaskFinishedEventArgs> _taskFinishedHandler; [NotNull] private readonly IBuildEventHandler<BuildErrorEventArgs> _errorHandler; [NotNull] private readonly IBuildEventHandler<BuildWarningEventArgs> _warningHandler; [NotNull] private readonly IBuildEventHandler<CustomBuildEventArgs> _customEventHandler; [NotNull] private readonly IBuildEventHandler<BuildStartedEventArgs> _buildStartedEventHandler; [NotNull] private readonly IParametersParser _parametersParser; [NotNull] private readonly ILogWriter _logWriter; [NotNull] private readonly object _lockObject = new object(); // ReSharper disable once IdentifierTypo private int _reentrancy; public NodeLogger( // ReSharper disable once UnusedParameter.Local // ReSharper disable once IdentifierTypo [NotNull] Parameters parameters, [NotNull] IInitializable[] initializables, [NotNull] IParametersParser parametersParser, [NotNull] ILogWriter logWriter, [NotNull] ILoggerContext context, [NotNull] IEnvironment environment, [NotNull] IDiagnostics diagnostics, [NotNull] IEventRegistry eventRegistry, [NotNull] IBuildEventHandler<BuildStartedEventArgs> buildStartedHandler, [NotNull] IBuildEventHandler<BuildMessageEventArgs> messageHandler, [NotNull] IBuildEventHandler<BuildFinishedEventArgs> buildFinishedHandler, [NotNull] IBuildEventHandler<ProjectStartedEventArgs> projectStartedHandler, [NotNull] IBuildEventHandler<ProjectFinishedEventArgs> projectFinishedHandler, [NotNull] IBuildEventHandler<TargetStartedEventArgs> targetStartedHandler, [NotNull] IBuildEventHandler<TargetFinishedEventArgs> targetFinishedHandler, [NotNull] IBuildEventHandler<TaskStartedEventArgs> taskStartedHandler, [NotNull] IBuildEventHandler<TaskFinishedEventArgs> taskFinishedHandler, [NotNull] IBuildEventHandler<BuildErrorEventArgs> errorHandler, [NotNull] IBuildEventHandler<BuildWarningEventArgs> warningHandler, [NotNull] IBuildEventHandler<CustomBuildEventArgs> customEventHandler) { _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); _context = context ?? throw new ArgumentNullException(nameof(context)); _environment = environment ?? throw new ArgumentNullException(nameof(environment)); _diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics)); _eventRegistry = eventRegistry; _parametersParser = parametersParser ?? throw new ArgumentNullException(nameof(parametersParser)); _logWriter = logWriter ?? throw new ArgumentNullException(nameof(logWriter)); _buildStartedEventHandler = buildStartedHandler ?? throw new ArgumentNullException(nameof(buildStartedHandler)); _messageHandler = messageHandler ?? throw new ArgumentNullException(nameof(messageHandler)); _buildFinishedHandler = buildFinishedHandler ?? throw new ArgumentNullException(nameof(buildFinishedHandler)); _projectStartedHandler = projectStartedHandler ?? throw new ArgumentNullException(nameof(projectStartedHandler)); _projectFinishedHandler = projectFinishedHandler ?? throw new ArgumentNullException(nameof(projectFinishedHandler)); _targetStartedHandler = targetStartedHandler ?? throw new ArgumentNullException(nameof(targetStartedHandler)); _targetFinishedHandler = targetFinishedHandler ?? throw new ArgumentNullException(nameof(targetFinishedHandler)); _taskStartedHandler = taskStartedHandler ?? throw new ArgumentNullException(nameof(taskStartedHandler)); _taskFinishedHandler = taskFinishedHandler ?? throw new ArgumentNullException(nameof(taskFinishedHandler)); _errorHandler = errorHandler ?? throw new ArgumentNullException(nameof(errorHandler)); _warningHandler = warningHandler ?? throw new ArgumentNullException(nameof(warningHandler)); _customEventHandler = customEventHandler ?? throw new ArgumentNullException(nameof(customEventHandler)); } // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once UnusedAutoPropertyAccessor.Global public bool SkipProjectStartedText { get; set; } // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once UnusedMember.Global public bool ShowSummary { get => _parameters.ShowSummary ?? false; // ReSharper disable once UnusedMember.Global set => _parameters.ShowSummary = value; } public LoggerVerbosity Verbosity { get; set; } = LoggerVerbosity.Normal; public string Parameters { get; set; } public void Initialize(IEventSource eventSource, int nodeCount) { _diagnostics.Send(() => $"Initialize({eventSource}, {nodeCount})"); _parameters.Verbosity = Verbosity; if (Parameters != null) { if (!_parametersParser.TryParse(Parameters, _parameters, out var error)) { throw new LoggerException(error); } } _context.Initialize( nodeCount, SkipProjectStartedText, _parameters); if (nodeCount == 1 && _parameters.ShowEventId.HasValue) { _parameters.ShowEventId = false; } if (_parameters.Debug) { try { _logWriter.SetColor(Color.Warning); _logWriter.Write($"\nWaiting for debugger in process: [{Process.GetCurrentProcess().Id}] \"{Process.GetCurrentProcess().ProcessName}\"\n"); } finally { _logWriter.ResetColor(); } while (!Debugger.IsAttached) { Thread.Sleep(100); } Debugger.Break(); } if (_context.IsVerbosityAtLeast(LoggerVerbosity.Diagnostic)) { _parameters.ShowPerfSummary = true; } _parameters.ShowTargetOutputs = _environment.TargetOutputLogging; if (!_parameters.ShowSummary.HasValue && _context.IsVerbosityAtLeast(LoggerVerbosity.Normal)) { _parameters.ShowSummary = true; } if (_parameters.ShowOnlyWarnings || _parameters.ShowOnlyErrors) { if (!_parameters.ShowSummary.HasValue) { _parameters.ShowSummary = false; } _parameters.ShowPerfSummary = false; } if (_context.IsVerbosityAtLeast(LoggerVerbosity.Diagnostic)) { try { _logWriter.SetColor(Color.Details); _logWriter.Write($"Logger parameters: {_parameters}\n"); } finally { _logWriter.ResetColor(); } } eventSource.BuildStarted += (sender, e) => Handle(_buildStartedEventHandler, e); eventSource.BuildFinished += (sender, e) => Handle(_buildFinishedHandler, e); eventSource.ProjectStarted += (sender, e) => Handle(_projectStartedHandler, e); eventSource.ProjectFinished += (sender, e) => Handle(_projectFinishedHandler, e); eventSource.TargetStarted += (sender, e) => Handle(_targetStartedHandler, e); eventSource.TargetFinished += (sender, e) => Handle(_targetFinishedHandler, e); eventSource.TaskStarted += (sender, e) => Handle(_taskStartedHandler, e); eventSource.TaskFinished += (sender, e) => Handle(_taskFinishedHandler, e); eventSource.ErrorRaised += (sender, e) => Handle(_errorHandler, e); eventSource.WarningRaised += (sender, e) => Handle(_warningHandler, e); eventSource.MessageRaised += (sender, e) => Handle(_messageHandler, e); eventSource.CustomEventRaised += (sender, e) => Handle(_customEventHandler, e); _diagnostics.Send(() => _parameters.ToString()); } public void Initialize(IEventSource eventSource) { Initialize(eventSource, 1); } public virtual void Shutdown() { _diagnostics.Send(() => "Shutdown()"); } private void Handle<TBuildEventArgs>(IBuildEventHandler<TBuildEventArgs> handler, TBuildEventArgs e) where TBuildEventArgs : BuildEventArgs { if (e == null) { return; } // ReSharper disable once IdentifierTypo var reentrancy = Interlocked.Increment(ref _reentrancy) - 1; // ReSharper disable once AccessToModifiedClosure _diagnostics.Send(() => $"[{reentrancy} +] Handle<{typeof(TBuildEventArgs).Name}>()"); try { lock (_lockObject) { using (_eventRegistry.Register(e)) using (new HierarchicalContext(e.BuildEventContext?.NodeId ?? 0)) { handler.Handle(e); } } } catch (Exception ex) { var error = $"Exception was occurred while processing a message of type \"{e.GetType()}\":\n{ex}"; _logWriter.Write(error); _diagnostics.Send(() => error); } finally { reentrancy = Interlocked.Decrement(ref _reentrancy); _diagnostics.Send(() => $"[{reentrancy} -] Handle<{typeof(TBuildEventArgs).Name}>()"); } } } }