File: LoggerExtensions.cs
Web Access
Project: src\src\Microsoft.DotNet.Helix\Sdk\Microsoft.DotNet.Helix.Sdk.csproj (Microsoft.DotNet.Helix.Sdk)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.Build.Utilities;
 
namespace Microsoft.DotNet.Helix.Sdk
{
    public static class LoggerExtensions
    {
        private const string EventName = "NETCORE_ENGINEERING_TELEMETRY";
        private const string CategoryKey = "Category";
 
        private static readonly AsyncLocal<ImmutableStack<string>> s_localCategoryStack = new AsyncLocal<ImmutableStack<string>>();
 
        private static ImmutableStack<string> CategoryStack
        {
            get => s_localCategoryStack.Value ?? ImmutableStack<string>.Empty;
            set => s_localCategoryStack.Value = value;
        }
 
        public static FailureCategoryScope EnterFailureCategoryScope(this TaskLoggingHelper log, FailureCategory category)
        {
            if (log == null)
            {
                throw new ArgumentNullException(nameof(log));
            }
            CategoryStack = CategoryStack.Push(category.Value);
            UpdateCategory(log);
            return new FailureCategoryScope(log);
        }
 
        private static void UpdateCategory(TaskLoggingHelper log)
        {
            string currentCategory = CategoryStack.IsEmpty ? "" : CategoryStack.Peek();
            log.LogTelemetry(EventName, new Dictionary<string, string> {{CategoryKey, currentCategory}});
        }
 
        public static void LogError(this TaskLoggingHelper log, FailureCategory category, string message, params object[] messageArgs)
        {
            using (EnterFailureCategoryScope(log, category))
            {
                log.LogError(message, messageArgs);
            }
        }
 
        public static void LogErrorFromException(
            this TaskLoggingHelper log,
            FailureCategory category,
            Exception exception,
            bool showStackTrace = false,
            bool showDetail = false,
            string file = null)
        {
            using (EnterFailureCategoryScope(log, category))
            {
                log.LogErrorFromException(exception, showStackTrace, showDetail, file);
            }
        }
 
        public struct FailureCategoryScope : IDisposable
        {
            private TaskLoggingHelper _log;
 
            public FailureCategoryScope(TaskLoggingHelper log)
            {
                _log = log;
            }
 
            public void Dispose()
            {
                if (_log == null)
                    return;
                CategoryStack = CategoryStack.Pop();
                UpdateCategory(_log);
                _log = null;
            }
        }
    }
}