forked from open-telemetry/opentelemetry-dotnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLogRecord.cs
More file actions
186 lines (153 loc) · 6.54 KB
/
Copy pathLogRecord.cs
File metadata and controls
186 lines (153 loc) · 6.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// <copyright file="LogRecord.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#if NET461 || NETSTANDARD2_0
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
namespace OpenTelemetry.Logs
{
/// <summary>
/// Stores details about a log message.
/// </summary>
public sealed class LogRecord
{
private static readonly Action<object, List<object>> AddScopeToBufferedList = (object scope, List<object> state) =>
{
state.Add(scope);
};
private List<object> bufferedScopes;
internal LogRecord(
IExternalScopeProvider scopeProvider,
DateTime timestamp,
string categoryName,
LogLevel logLevel,
EventId eventId,
string formattedMessage,
object state,
Exception exception,
IReadOnlyList<KeyValuePair<string, object>> stateValues)
{
this.ScopeProvider = scopeProvider;
var activity = Activity.Current;
if (activity != null)
{
this.TraceId = activity.TraceId;
this.SpanId = activity.SpanId;
this.TraceState = activity.TraceStateString;
this.TraceFlags = activity.ActivityTraceFlags;
}
this.Timestamp = timestamp;
this.CategoryName = categoryName;
this.LogLevel = logLevel;
this.EventId = eventId;
this.FormattedMessage = formattedMessage;
this.State = state;
this.StateValues = stateValues;
this.Exception = exception;
}
public DateTime Timestamp { get; }
public ActivityTraceId TraceId { get; }
public ActivitySpanId SpanId { get; }
public ActivityTraceFlags TraceFlags { get; }
public string TraceState { get; }
public string CategoryName { get; }
public LogLevel LogLevel { get; }
public EventId EventId { get; }
public string FormattedMessage { get; }
/// <summary>
/// Gets the raw state attached to the log. Set to <see
/// langword="null"/> when <see
/// cref="OpenTelemetryLoggerOptions.ParseStateValues"/> is enabled.
/// </summary>
public object State { get; }
/// <summary>
/// Gets the parsed state values attached to the log. Set when <see
/// cref="OpenTelemetryLoggerOptions.ParseStateValues"/> is enabled
/// otherwise <see langword="null"/>.
/// </summary>
public IReadOnlyList<KeyValuePair<string, object>> StateValues { get; }
public Exception Exception { get; }
internal IExternalScopeProvider ScopeProvider { get; set; }
/// <summary>
/// Executes callback for each currently active scope objects in order
/// of creation. All callbacks are guaranteed to be called inline from
/// this method.
/// </summary>
/// <remarks>
/// Note: Scopes are only available during the lifecycle of the log
/// message being written. If you need to capture scopes to be used
/// later (for example in batching scenarios), call <see
/// cref="BufferLogScopes"/> to safely capture the values (incurs
/// allocation).
/// </remarks>
/// <typeparam name="TState">State.</typeparam>
/// <param name="callback">The callback to be executed for every scope object.</param>
/// <param name="state">The state object to be passed into the callback.</param>
public unsafe void ForEachScope<TState>(LogRecordScopeCallback<TState> callback, TState state)
{
if (this.bufferedScopes != null)
{
ScopeForEachState<TState> forEachState = new ScopeForEachState<TState>(callback, state, 0);
IntPtr statePointer = new IntPtr(Unsafe.AsPointer(ref forEachState));
foreach (object scope in this.bufferedScopes)
{
ScopeForEachState<TState>.ForEachScope(scope, statePointer);
}
}
else if (this.ScopeProvider != null)
{
ScopeForEachState<TState> forEachState = new ScopeForEachState<TState>(callback, state, 0);
IntPtr statePointer = new IntPtr(Unsafe.AsPointer(ref forEachState));
this.ScopeProvider.ForEachScope(ScopeForEachState<TState>.ForEachScope, statePointer);
}
}
/// <summary>
/// Buffers the scopes attached to the log into a list so that they can
/// be safely processed after the log message lifecycle has ended.
/// </summary>
public void BufferLogScopes()
{
if (this.ScopeProvider == null || this.bufferedScopes != null)
{
return;
}
List<object> scopes = new List<object>();
this.ScopeProvider?.ForEachScope(AddScopeToBufferedList, scopes);
this.bufferedScopes = scopes;
}
private unsafe struct ScopeForEachState<TState>
{
public static readonly Action<object, IntPtr> ForEachScope = (object scope, IntPtr statePointer) =>
{
ref ScopeForEachState<TState> state = ref Unsafe.AsRef<ScopeForEachState<TState>>((void*)statePointer);
LogRecordScope logRecordScope = new LogRecordScope(scope, state.Depth++);
state.Callback(logRecordScope, state.UserState);
};
public readonly LogRecordScopeCallback<TState> Callback;
public readonly TState UserState;
public int Depth;
public ScopeForEachState(LogRecordScopeCallback<TState> callback, TState state, int depth)
{
this.Callback = callback;
this.UserState = state;
this.Depth = depth;
}
}
}
}
#endif