< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 48
Coverable lines: 48
Total lines: 221
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 31
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
Info(...)0%220%
Info(...)100%110%
Info(...)0%220%
IdOf(...)0%220%
GetHashCode(...)0%220%
Format(...)0%16160%
Format(...)0%770%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/Common/src/System/Net/Logging/NetEventSource.Common.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections;
 5using System.Diagnostics;
 6using System.Diagnostics.CodeAnalysis;
 7using System.Diagnostics.Tracing;
 8using System.Runtime.CompilerServices;
 9using System.Runtime.InteropServices;
 10
 11#pragma warning disable CA1823 // not all IDs are used by all partial providers
 12
 13namespace System.Net
 14{
 15    // Implementation:
 16    // This partial file is meant to be consumed into each System.Net.* assembly that needs to log.  Each such assembly 
 17    // its own NetEventSource partial class that adds an appropriate [EventSource] attribute, giving it a unique name fo
 18    // Those partials can then also add additional events if needed, starting numbering from the NextAvailableEventId de
 19
 20    // Usage:
 21    // - Operations that may allocate (e.g. boxing a value type, using string interpolation, etc.) or that may have comp
 22    //   at call sites should guard access like:
 23    //       if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(null, $"Found certificate: {cert}"); // info loggin
 24    // - Operations that have zero allocations / measurable computations at call sites can use a simpler pattern, callin
 25    //       NetEventSource.Info(this, "literal string");  // arbitrary message with a literal string
 26    //   Debug.Asserts inside the logging methods will help to flag some misuse if the DEBUG_NETEVENTSOURCE_MISUSE compi
 27    //   However, because it can be difficult by observation to understand all of the costs involved, guarding can be do
 28    // - Messages can be strings, formattable strings, or any other object.  Objects (including those used in formattabl
 29    //   formatting applied, controlled by the Format method.  Partial specializations can also override this formatting
 30    //   method that takes an object and optionally provides a string representation of it, in case a particular library
 31
 32    /// <summary>Provides logging facilities for System.Net libraries.</summary>
 33    internal sealed partial class NetEventSource : EventSource
 34    {
 35        private const string EventSourceSuppressMessage = "Parameters to this method are primitive and are trimmer safe"
 36
 37        /// <summary>The single event source instance to use for all logging.</summary>
 038        public static readonly NetEventSource Log = new NetEventSource();
 39
 40        #region Metadata
 41        private const string MissingMember = "(?)";
 42        private const string NullInstance = "(null)";
 43        private const string StaticMethodObject = "(static)";
 44        private const string NoParameters = "";
 45
 46        private const int InfoEventId = 1;
 47        private const int ErrorEventId = 2;
 48        // private const int AssociateEventId = 3; // Defined in NetEventSource.Common.Associate.cs
 49        // private const int DumpArrayEventId = 4; // Defined in NetEventSource.Common.DumpBuffer.cs
 50
 51        private const int NextAvailableEventId = 5; // Update this value whenever new events are added.  Derived types s
 52        #endregion
 53
 54        #region Info
 55        /// <summary>Logs an information message.</summary>
 56        /// <param name="thisOrContextObject">`this`, or another object that serves to provide context for the operation
 57        /// <param name="formattableString">The message to be logged.</param>
 58        /// <param name="memberName">The calling member.</param>
 59        [NonEvent]
 60        public static void Info(object? thisOrContextObject, FormattableString? formattableString = null, [CallerMemberN
 061            Log.Info(IdOf(thisOrContextObject), memberName, formattableString != null ? Format(formattableString) : NoPa
 62
 63        /// <summary>Logs an information message.</summary>
 64        /// <param name="thisOrContextObject">`this`, or another object that serves to provide context for the operation
 65        /// <param name="message">The message to be logged.</param>
 66        /// <param name="memberName">The calling member.</param>
 67        [NonEvent]
 68        public static void Info(object? thisOrContextObject, object? message, [CallerMemberName] string? memberName = nu
 069            Log.Info(IdOf(thisOrContextObject), memberName, Format(message));
 70
 71        [Event(InfoEventId, Level = EventLevel.Informational)]
 72        private void Info(string thisOrContextObject, string? memberName, string? message)
 073        {
 074            Debug.Assert(IsEnabled());
 075            WriteEvent(InfoEventId, thisOrContextObject, memberName ?? MissingMember, message);
 076        }
 77        #endregion
 78
 79        #region Error
 80        /// <summary>Logs an error message.</summary>
 81        /// <param name="thisOrContextObject">`this`, or another object that serves to provide context for the operation
 82        /// <param name="formattableString">The message to be logged.</param>
 83        /// <param name="memberName">The calling member.</param>
 84        [NonEvent]
 85        public static void Error(object? thisOrContextObject, FormattableString formattableString, [CallerMemberName] st
 86            Log.ErrorMessage(IdOf(thisOrContextObject), memberName, Format(formattableString));
 87
 88        /// <summary>Logs an error message.</summary>
 89        /// <param name="thisOrContextObject">`this`, or another object that serves to provide context for the operation
 90        /// <param name="message">The message to be logged.</param>
 91        /// <param name="memberName">The calling member.</param>
 92        [NonEvent]
 93        public static void Error(object? thisOrContextObject, object message, [CallerMemberName] string? memberName = nu
 94            Log.ErrorMessage(IdOf(thisOrContextObject), memberName, Format(message));
 95
 96        [Event(ErrorEventId, Level = EventLevel.Error)]
 97        private void ErrorMessage(string thisOrContextObject, string? memberName, string? message)
 98        {
 99            Debug.Assert(IsEnabled());
 100            WriteEvent(ErrorEventId, thisOrContextObject, memberName ?? MissingMember, message);
 101        }
 102        #endregion
 103
 104        #region Helpers
 105        [NonEvent]
 0106        public static string IdOf(object? value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : Nu
 107
 108        [NonEvent]
 0109        public static int GetHashCode(object? value) => value?.GetHashCode() ?? 0;
 110
 111        [NonEvent]
 112        public static string? Format(object? value)
 0113        {
 114            // If it's null, return a known string for null values
 0115            if (value == null)
 0116            {
 0117                return NullInstance;
 118            }
 119
 120            // Give another partial implementation a chance to provide its own string representation
 0121            string? result = null;
 122            AdditionalCustomizedToString(value, ref result);
 0123            if (result is not null)
 0124            {
 0125                return result;
 126            }
 127
 128            // Format arrays with their element type name and length
 0129            if (value is Array arr)
 0130            {
 0131                return $"{arr.GetType().GetElementType()}[{((Array)value).Length}]";
 132            }
 133
 134            // Format ICollections as the name and count
 0135            if (value is ICollection c)
 0136            {
 0137                return $"{c.GetType().Name}({c.Count})";
 138            }
 139
 140            // Format SafeHandles as their type, hash code, and pointer value
 0141            if (value is SafeHandle handle)
 0142            {
 0143                return $"{handle.GetType().Name}:{handle.GetHashCode()}(0x{handle.DangerousGetHandle():X})";
 144            }
 145
 146            // Format IntPtrs as hex
 0147            if (value is IntPtr)
 0148            {
 0149                return $"0x{value:X}";
 150            }
 151
 152            // If the string representation of the instance would just be its type name,
 153            // use its id instead.
 0154            string? toString = value.ToString();
 0155            if (toString == null || toString == value.GetType().FullName)
 0156            {
 0157                return IdOf(value);
 158            }
 159
 160            // Otherwise, return the original object so that the caller does default formatting.
 0161            return value.ToString();
 0162        }
 163
 164        [NonEvent]
 165        private static string Format(FormattableString s)
 0166        {
 0167            switch (s.ArgumentCount)
 168            {
 0169                case 0: return s.Format;
 0170                case 1: return string.Format(s.Format, Format(s.GetArgument(0)));
 0171                case 2: return string.Format(s.Format, Format(s.GetArgument(0)), Format(s.GetArgument(1)));
 0172                case 3: return string.Format(s.Format, Format(s.GetArgument(0)), Format(s.GetArgument(1)), Format(s.GetA
 173                default:
 0174                    string?[] formattedArgs = new string?[s.ArgumentCount];
 0175                    for (int i = 0; i < formattedArgs.Length; i++)
 0176                    {
 0177                        formattedArgs[i] = Format(s.GetArgument(i));
 0178                    }
 0179                    return string.Format(s.Format, formattedArgs);
 180            }
 0181        }
 182
 183        static partial void AdditionalCustomizedToString(object value, ref string? result);
 184        #endregion
 185
 186        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
 187                   Justification = EventSourceSuppressMessage)]
 188        [NonEvent]
 189        private unsafe void WriteEvent(int eventId, string? arg1, string? arg2, int arg3)
 190        {
 191            arg1 ??= "";
 192            arg2 ??= "";
 193
 194            fixed (char* arg1Ptr = arg1)
 195            fixed (char* arg2Ptr = arg2)
 196            {
 197                const int NumEventDatas = 3;
 198                EventData* descrs = stackalloc EventData[NumEventDatas];
 199
 200                descrs[0] = new EventData
 201                {
 202                    DataPointer = (IntPtr)(arg1Ptr),
 203                    Size = (arg1.Length + 1) * sizeof(char)
 204                };
 205                descrs[1] = new EventData
 206                {
 207                    DataPointer = (IntPtr)(arg2Ptr),
 208                    Size = (arg2.Length + 1) * sizeof(char)
 209                };
 210                descrs[2] = new EventData
 211                {
 212                    DataPointer = (IntPtr)(&arg3),
 213                    Size = sizeof(int)
 214                };
 215
 216                WriteEventCore(eventId, NumEventDatas, descrs);
 217            }
 218        }
 219    }
 220}
 221