Skip to content

Commit f92f503

Browse files
authored
[log4net] bridge + trace context injection (#3825)
1 parent 9a4cd41 commit f92f503

File tree

38 files changed

+1442
-13
lines changed

38 files changed

+1442
-13
lines changed

.cspell/company-terms.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
appender
2+
appenders
13
CNCF
24
opentelemetry
35
OTEL
46
OTLP
5-
tracecontext
6-
triager
7-
Zipkin
87
parentbased
8+
tracecontext
99
traceidratio
10+
triager
11+
Zipkin

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h
1212
- Support for .NET9.
1313
- Support for [RabbitMQ.Client](https://www.nuget.org/packages/RabbitMQ.Client/)
1414
traces instrumentation for versions `7.0.0`+.
15+
- [log4net](https://www.nuget.org/packages/log4net/) [OpenTelemetry appender](https://opentelemetry.io/docs/concepts/signals/logs/#log-appender--bridge)
16+
for versions >= `2.0.13` && < `4.0.0`
1517
- Support for SqlClient metrics.
1618

1719
### Changed

Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
<PropertyGroup>
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
5-
65
<ItemGroup>
76
<PackageVersion Include="DotNet.ReproducibleBuilds" Version="1.2.25" />
7+
<PackageVersion Include="log4net" Version="3.0.3" />
88
<PackageVersion Include="MinVer" Version="6.0.0" />
99
<PackageVersion Include="OpenTelemetry" Version="1.10.0" />
1010
<PackageVersion Include="OpenTelemetry.Api" Version="1.10.0" />
@@ -13,4 +13,4 @@
1313
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
1414
<PackageVersion Include="OpenTelemetry.Instrumentation.Wcf" Version="1.10.0-beta.1" />
1515
</ItemGroup>
16-
</Project>
16+
</Project>

OpenTelemetry.AutoInstrumentation.sln

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.Owin.IIS.Ne
245245
EndProject
246246
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SdkVersionAnalyzer", "tools\SdkVersionAnalyzer\SdkVersionAnalyzer.csproj", "{C75FA076-D460-414B-97F7-6F8D0E85AE74}"
247247
EndProject
248+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.Log4NetBridge", "test\test-applications\integrations\TestApplication.Log4NetBridge\TestApplication.Log4NetBridge.csproj", "{926B7C03-42C2-4192-94A7-CD0B1C693279}"
249+
EndProject
248250
Global
249251
GlobalSection(SolutionConfigurationPlatforms) = preSolution
250252
Debug|Any CPU = Debug|Any CPU
@@ -1513,6 +1515,22 @@ Global
15131515
{C75FA076-D460-414B-97F7-6F8D0E85AE74}.Release|x64.Build.0 = Release|Any CPU
15141516
{C75FA076-D460-414B-97F7-6F8D0E85AE74}.Release|x86.ActiveCfg = Release|Any CPU
15151517
{C75FA076-D460-414B-97F7-6F8D0E85AE74}.Release|x86.Build.0 = Release|Any CPU
1518+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1519+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|Any CPU.Build.0 = Debug|Any CPU
1520+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|ARM64.ActiveCfg = Debug|Any CPU
1521+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|ARM64.Build.0 = Debug|Any CPU
1522+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|x64.ActiveCfg = Debug|Any CPU
1523+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|x64.Build.0 = Debug|Any CPU
1524+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|x86.ActiveCfg = Debug|Any CPU
1525+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Debug|x86.Build.0 = Debug|Any CPU
1526+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|Any CPU.ActiveCfg = Release|Any CPU
1527+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|Any CPU.Build.0 = Release|Any CPU
1528+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|ARM64.ActiveCfg = Release|Any CPU
1529+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|ARM64.Build.0 = Release|Any CPU
1530+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|x64.ActiveCfg = Release|Any CPU
1531+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|x64.Build.0 = Release|Any CPU
1532+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|x86.ActiveCfg = Release|Any CPU
1533+
{926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|x86.Build.0 = Release|Any CPU
15161534
EndGlobalSection
15171535
GlobalSection(SolutionProperties) = preSolution
15181536
HideSolutionNode = FALSE
@@ -1602,6 +1620,7 @@ Global
16021620
{91D883EC-069E-46BC-B6F7-67C94299851E} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
16031621
{AA3E0C5C-A4E2-46AB-BD18-2D30D3ABF692} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
16041622
{C75FA076-D460-414B-97F7-6F8D0E85AE74} = {00F4C92D-6652-4BD8-A334-B35D3E711BE6}
1623+
{926B7C03-42C2-4192-94A7-CD0B1C693279} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
16051624
EndGlobalSection
16061625
GlobalSection(ExtensibilityGlobals) = postSolution
16071626
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}

build/LibraryVersions.g.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ public static partial class LibraryVersion
6767
new("2.67.0"),
6868
}
6969
},
70+
{
71+
"TestApplication.Log4NetBridge",
72+
new List<PackageBuildInfo>
73+
{
74+
new("2.0.13"),
75+
new("3.0.3"),
76+
}
77+
},
7078
{
7179
"TestApplication.MassTransit",
7280
new List<PackageBuildInfo>

docs/config.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ due to lack of stable semantic convention.
207207
| ID | Instrumented library | Supported versions | Instrumentation type | Status |
208208
|-----------|---------------------------------------------------------------------------------------------------------------------------------|--------------------|------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
209209
| `ILOGGER` | [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) **Not supported on .NET Framework** | ≥9.0.0 | bytecode or source [1] | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
210+
| `LOG4NET` | [log4net](https://www.nuget.org/packages/log4net) | ≥2.0.13 && < 4.0.0 | bytecode | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
210211

211212
**[1]**: For ASP.NET Core applications, the `LoggingBuilder` instrumentation
212213
can be enabled without using the .NET CLR Profiler by setting

docs/internal/log4net.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# `log4net` instrumentation
2+
3+
> [!IMPORTANT]
4+
> log4net bridge and trace context injection are experimental features.
5+
> Both instrumentations can be disabled by setting `OTEL_DOTNET_AUTO_LOGS_LOG4NET_INSTRUMENTATION_ENABLED` to `false`.
6+
7+
Both bridge and trace context injection are supported for `log4net` in versions >= 2.0.13 && < 4.0.0
8+
9+
## `log4net` [logs bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge)
10+
11+
The `log4net` logs bridge is disabled by default. In order to enable it, set `OTEL_DOTNET_AUTO_LOGS_ENABLE_LOG4NET_BRIDGE` to `true`.
12+
When `log4net` logs bridge is enabled, and `log4net` is configured with at least 1 appender, application logs are exported in OTLP
13+
format by default to the local instance of OpenTelemetry Collector, in addition to being written into their currently configured destination (e.g. a file).
14+
15+
### `log4net` logging events conversion
16+
17+
`log4net`'s `LoggingEvent`s are converted to OpenTelemetry log records in a following way:
18+
19+
- `TimeStampUtc` is set as a `Timestamp`
20+
- `Level.Name` is set as a `SeverityText`
21+
- If formatted strings were used for logging (e.g. by using `InfoFormat` or similar), format string is set as a `Body`
22+
- Otherwise, `RenderedMessage` is set as a `Body`
23+
- If formatted strings were used for logging, format arguments are added as attributes, with indexes as their names
24+
- If formatted strings were used for logging, and `OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE` is set, rendered message
25+
is added as `log4net.rendered_message` attribute
26+
- `LoggerName` is set as an `InstrumentationScope.Name`
27+
- `Properties`, apart from builtin properties prefixed with `log4net:`, are added as attributes
28+
- `Exception` is used to populate the following properties: `exception.type`,`exception.message`,`exception.stacktrace`
29+
- `Level.Value` is mapped to `SeverityNumber` as outlined in the next section
30+
31+
#### `log4net` level severity mapping
32+
33+
`log4net` levels are mapped to OpenTelemetry severity types according to the following rules based on their numerical values.
34+
35+
Levels with numerical values of:
36+
37+
- Equal to `Level.Fatal` or higher are mapped to `LogRecordSeverity.Fatal`
38+
- Higher than or equal to `Level.Error` but lower than `Level.Fatal` are mapped to `LogRecordSeverity.Error`
39+
- Higher than or equal to `Level.Warn` but lower than `Level.Error` are mapped to `LogRecordSeverity.Warn`
40+
- Higher than or equal to `Level.Info` but lower than `Level.Warn` are mapped to `LogRecordSeverity.Info`
41+
- Higher than or equal to `Level.Debug` but lower than `Level.Info` are mapped to `LogRecordSeverity.Debug`
42+
- Lower than `Level.Debug` are mapped to `LogRecordSeverity.Trace`
43+
44+
## `log4net` trace context injection
45+
46+
Following properties are added by default to the collection of logging event's properties:
47+
48+
- `trace_id`
49+
- `span_id`
50+
- `trace_flags`
51+
52+
This allows for trace context to be logged into currently configured log destination, e.g. a file.
53+
In order to use them, pattern needs to be updated.
54+
55+
## Known limitations of `log4net` bridge
56+
57+
In order for the bridge to be added, at least 1 other appender has to be configured.
58+
Bridge should not be used when appenders are configured for both root and component loggers.
59+
Enabling a bridge in such scenario would result in bridge being appended to both appender collections,
60+
and logs duplication.
61+
62+
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
OpenTelemetry.AutoInstrumentation.Instrumentations.Log4Net.Bridge.Integrations.AppenderCollectionIntegration
2+
OpenTelemetry.AutoInstrumentation.Instrumentations.Log4Net.TraceContextInjection.Integrations.AppenderAttachedImplIntegration
13
OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.Integrations.MongoClientIntegrationExecute
2-
OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.Integrations.MongoClientIntegrationExecuteAsync
4+
OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.Integrations.MongoClientIntegrationExecuteAsync
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
OpenTelemetry.AutoInstrumentation.Instrumentations.Log4Net.Bridge.Integrations.AppenderCollectionIntegration
2+
OpenTelemetry.AutoInstrumentation.Instrumentations.Log4Net.TraceContextInjection.Integrations.AppenderAttachedImplIntegration
13
OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.Integrations.MongoClientIntegrationExecute
2-
OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.Integrations.MongoClientIntegrationExecuteAsync
4+
OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.Integrations.MongoClientIntegrationExecuteAsync

src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ public static class Logs
217217
/// </summary>
218218
public const string IncludeFormattedMessage = "OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE";
219219

220+
/// <summary>
221+
/// Configuration key for whether or not experimental log4net bridge
222+
/// should be enabled.
223+
/// </summary>
224+
public const string EnableLog4NetBridge = "OTEL_DOTNET_AUTO_LOGS_ENABLE_LOG4NET_BRIDGE";
225+
220226
/// <summary>
221227
/// Configuration key for disabling all log instrumentations.
222228
/// </summary>

0 commit comments

Comments
 (0)