Skip to content

Commit a967446

Browse files
authored
Merge pull request #148 from serilog/dev
4.0.0 Release
2 parents fa5588b + 6b7a63d commit a967446

38 files changed

+5151
-427
lines changed

.github/.DS_Store

6 KB
Binary file not shown.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
name: Bug report
3+
about: Report a bug and help us to improve Serilog.Sinks.OpenTelemetry
4+
title: ''
5+
labels: bug
6+
assignees: ''
7+
8+
---
9+
10+
The Serilog maintainers want you to have a great experience using Serilog.Sinks.OpenTelemetry, and will happily track down and resolve bugs. We all have limited time, though, so please think through all of the factors that might be involved and include as much useful information as possible 😊.
11+
12+
ℹ If the problem is caused by a sink or other extension package, please track down the correct repository for that package and create the report there: this tracker is for the **Serilog.Sinks.OpenTelemetry** package only.
13+
14+
**Description**
15+
What's going wrong?
16+
17+
**Reproduction**
18+
Please provide code samples showing how you're configuring and calling Serilog to produce the behavior.
19+
20+
**Expected behavior**
21+
A concise description of what you expected to happen.
22+
23+
**Relevant package, tooling and runtime versions**
24+
Which package versions are you using, on what platform?
25+
26+
**Additional context**
27+
Add any other context about the problem here.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
contact_links:
2+
- name: Ask for help
3+
url: https://github.com/serilog/serilog/wiki/Usage-help
4+
about: Ask the community for help on how to use Serilog
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Feature request
3+
about: Suggest an improvement to Serilog.Sinks.OpenTelemetry
4+
title: ''
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. `When [...], it would be great if [...]`.
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context or screenshots about the feature request here.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,5 @@ FodyWeavers.xsd
397397
# JetBrains Rider
398398
*.sln.iml
399399
/test/Serilog.Sinks.OpenTelemetry.Tests/PublicApiVisibilityTests.received.txt
400+
401+
.DS_Store

README.md

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ examples below.
3838

3939
## Configuration
4040

41-
This sink supports two configuration styles: inline and options. The
42-
inline configuration looks like:
41+
This sink supports two configuration styles: inline and options.
42+
Inline configuration is appropriate for simple, local logging
43+
setups, and looks like:
4344

4445
```csharp
4546
Log.Logger = new LoggerConfiguration()
@@ -49,10 +50,7 @@ Log.Logger = new LoggerConfiguration()
4950
.CreateLogger();
5051
```
5152

52-
This configuration is appropriate only for simple, local logging
53-
setups.
54-
55-
More complicated use cases will need to use the options
53+
More complicated use cases need to use options-style
5654
configuration, which looks like:
5755

5856
```csharp
@@ -63,35 +61,28 @@ Log.Logger = new LoggerConfiguration()
6361
options.Protocol = OtlpProtocol.HttpProtobuf;
6462
})
6563
.CreateLogger();
66-
6764
```
6865

6966
This supports the sink's full set of configuration options. See the
7067
`OpenTelemetrySinkOptions.cs` file for the full set of options.
71-
Some of the more imporant parameters are discussed in the following
68+
Some of the more important parameters are discussed in the following
7269
sections.
7370

7471
### Endpoint and protocol
7572

76-
The default endpoint is `http://localhost:4317`, which will send
77-
logs to an OpenTelemetry collector running on the same machine over
78-
the gRPC protocol. This is appropriate for testing or for using a
79-
local OpenTelemetry collector as a proxy for a downstream logging service.
73+
The default endpoint and protocol are `http://localhost:4317` and `OtlpProtocol.Grpc`.
8074

81-
In most production scenarios, you will want to set an endpoint. To do so,
82-
add the `endpoint` argument to the `WriteTo.OpenTelemetry()` call.
75+
In most production scenarios, you'll need to set an endpoint and protocol to suit your
76+
deployment environment. To do so, add the `endpoint` argument to the `WriteTo.OpenTelemetry()` call.
8377

84-
You may also want to set the protocol explicitly. The supported values
78+
You may also want to set the protocol. The supported values
8579
are:
8680

8781
- `OtlpProtocol.Grpc`: Sends a protobuf representation of the
8882
OpenTelemetry Logs over a gRPC connection (the default).
8983
- `OtlpProtocol.HttpProtobuf`: Sends a protobuf representation of the
9084
OpenTelemetry Logs over an HTTP connection.
9185

92-
When the `OtlpProtocol.HttpProtobuf` option is specified, the endpoint
93-
URL **must** include the full path, for example `http://localhost:4318/v1/logs`.
94-
9586
### Resource attributes
9687

9788
OpenTelemetry logs may contain a "resource" that provides metadata concerning
@@ -126,6 +117,15 @@ Log.Logger = new LoggerConfiguration()
126117
.CreateLogger();
127118
```
128119

120+
### Environment variable overrides
121+
122+
The sink also recognizes a selection of the `OTEL_OTLP_EXPORTER_*` environment variables described in
123+
the [OpenTelemetry documentation](https://opentelemetry.io/docs/specs/otel/protocol/exporter/), and will
124+
override programmatic configuration with any environment variable values present at runtime.
125+
126+
To switch off this behavior, pass `ignoreEnvironment: true` to the `WriteTo.OpenTelemetry()` configuration
127+
methods.
128+
129129
## Serilog `LogEvent` to OpenTelemetry log record mapping
130130

131131
The following table provides the mapping between the Serilog log
@@ -165,6 +165,24 @@ Log.Logger = new LoggerConfiguration()
165165
The example shows the default value; `IncludedData.MessageTemplateMD5HashAttribute` can
166166
also be used to add the MD5 hash of the message template.
167167

168+
## Sending traces through the sink
169+
170+
Serilog `LogEvents` that carry a `SpanStartTimestamp` property of type `DateTime` will be
171+
recognized as spans by this sink, and sent using the appropriate OpenTelemetry endpoint
172+
and schema. The properties recognized by the sink match the ones emitted by
173+
[SerilogTracing](https://github.com/serilog-tracing/serilog-tracing).
174+
175+
In addition to the field mapping performed for log records, events that represent trace
176+
spans can carry the special properties listed below.
177+
178+
Serilog `LogEvent` | OpenTelemetry `Span` | Comments |
179+
---------------------------------|----------------------|----------------------------------------|
180+
`MessageTemplate` | `Name` | |
181+
`Properties["ParentSpanId"]` | `ParentSpanId` | Value must be of type `ActivitySpanId` |
182+
`Properties["SpanKind"]` | `Kind` | Value must be of type `ActivityKind` |
183+
`Properties["SpanStartTimestamp"]` | `StartTimeUnixNano` | Value must be of type `DateTime`; .NET provides 100-nanosecond precision |
184+
`Timestamp` | `EndTimeUnixNano` | .NET provides 100-nanosecond precision |
185+
168186
## Example
169187

170188
The `example/Example` subdirectory contains an example application that logs
6 KB
Binary file not shown.

src/Serilog.Sinks.OpenTelemetry/OpenTelemetryLoggerConfigurationExtensions.cs

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
// ReSharper disable once RedundantUsingDirective
1516
using System.Net.Http;
16-
using Serilog.Configuration;
17-
using Serilog.Sinks.OpenTelemetry;
18-
using Serilog.Sinks.OpenTelemetry.Exporters;
17+
1918
using Serilog.Collections;
19+
using Serilog.Configuration;
2020
using Serilog.Core;
2121
using Serilog.Events;
22+
using Serilog.Sinks.OpenTelemetry;
23+
using Serilog.Sinks.OpenTelemetry.Configuration;
24+
using Serilog.Sinks.OpenTelemetry.Exporters;
25+
// ReSharper disable MemberCanBePrivate.Global
2226

2327
namespace Serilog;
2428

@@ -27,42 +31,72 @@ namespace Serilog;
2731
/// </summary>
2832
public static class OpenTelemetryLoggerConfigurationExtensions
2933
{
34+
// ReSharper disable once ReturnTypeCanBeNotNullable
3035
static HttpMessageHandler? CreateDefaultHttpMessageHandler() =>
3136
#if FEATURE_SOCKETS_HTTP_HANDLER
3237
new SocketsHttpHandler { ActivityHeadersPropagator = null };
3338
#else
3439
null;
3540
#endif
36-
41+
3742
/// <summary>
3843
/// Send log events to an OTLP exporter.
3944
/// </summary>
4045
/// <param name="loggerSinkConfiguration">
4146
/// The `WriteTo` configuration object.
4247
/// </param>
4348
/// <param name="configure">The configuration callback.</param>
49+
/// <param name="ignoreEnvironment">If false the configuration will be overridden with values
50+
/// from the <see href="https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/">OTLP Exporter
51+
/// Configuration environment variables</see>, if present.</param>
4452
public static LoggerConfiguration OpenTelemetry(
4553
this LoggerSinkConfiguration loggerSinkConfiguration,
46-
Action<BatchedOpenTelemetrySinkOptions> configure)
54+
Action<BatchedOpenTelemetrySinkOptions> configure,
55+
bool ignoreEnvironment = false)
4756
{
4857
if (configure == null) throw new ArgumentNullException(nameof(configure));
4958

5059
var options = new BatchedOpenTelemetrySinkOptions();
5160
configure(options);
5261

62+
if (!ignoreEnvironment)
63+
{
64+
OpenTelemetryEnvironment.Configure(options, Environment.GetEnvironmentVariable);
65+
}
66+
5367
var exporter = Exporter.Create(
54-
endpoint: options.Endpoint,
68+
logsEndpoint: options.LogsEndpoint,
69+
tracesEndpoint: options.TracesEndpoint,
5570
protocol: options.Protocol,
5671
headers: new Dictionary<string, string>(options.Headers),
5772
httpMessageHandler: options.HttpMessageHandler ?? CreateDefaultHttpMessageHandler());
5873

59-
var openTelemetrySink = new OpenTelemetrySink(
60-
exporter: exporter,
61-
formatProvider: options.FormatProvider,
62-
resourceAttributes: new Dictionary<string, object>(options.ResourceAttributes),
63-
includedData: options.IncludedData);
74+
ILogEventSink? logsSink = null, tracesSink = null;
75+
76+
if (options.LogsEndpoint != null)
77+
{
78+
var openTelemetryLogsSink = new OpenTelemetryLogsSink(
79+
exporter: exporter,
80+
formatProvider: options.FormatProvider,
81+
resourceAttributes: new Dictionary<string, object>(options.ResourceAttributes),
82+
includedData: options.IncludedData);
6483

65-
return loggerSinkConfiguration.Sink(openTelemetrySink, options.BatchingOptions, options.RestrictedToMinimumLevel, options.LevelSwitch);
84+
logsSink = LoggerSinkConfiguration.CreateSink(wt => wt.Sink(openTelemetryLogsSink, options.BatchingOptions));
85+
}
86+
87+
if (options.TracesEndpoint != null)
88+
{
89+
var openTelemetryTracesSink = new OpenTelemetryTracesSink(
90+
exporter: exporter,
91+
resourceAttributes: new Dictionary<string, object>(options.ResourceAttributes),
92+
includedData: options.IncludedData);
93+
94+
tracesSink = LoggerSinkConfiguration.CreateSink(wt => wt.Sink(openTelemetryTracesSink, options.BatchingOptions));
95+
}
96+
97+
var sink = new OpenTelemetrySink(exporter, logsSink, tracesSink);
98+
99+
return loggerSinkConfiguration.Sink(sink, options.RestrictedToMinimumLevel, options.LevelSwitch);
66100
}
67101

68102
/// <summary>
@@ -117,7 +151,7 @@ public static LoggerConfiguration OpenTelemetry(
117151
resourceAttributes?.AddTo(options.ResourceAttributes);
118152
});
119153
}
120-
154+
121155
/// <summary>
122156
/// Audit to an OTLP exporter, waiting for each event to be acknowledged, and propagating errors to the caller.
123157
/// </summary>
@@ -132,20 +166,35 @@ public static LoggerConfiguration OpenTelemetry(
132166
if (configure == null) throw new ArgumentNullException(nameof(configure));
133167

134168
var options = new OpenTelemetrySinkOptions();
135-
136169
configure(options);
137170

138171
var exporter = Exporter.Create(
139-
endpoint: options.Endpoint,
172+
logsEndpoint: options.LogsEndpoint,
173+
tracesEndpoint: options.TracesEndpoint,
140174
protocol: options.Protocol,
141175
headers: new Dictionary<string, string>(options.Headers),
142176
httpMessageHandler: options.HttpMessageHandler ?? CreateDefaultHttpMessageHandler());
143177

144-
var sink = new OpenTelemetrySink(
145-
exporter: exporter,
146-
formatProvider: options.FormatProvider,
147-
resourceAttributes: new Dictionary<string, object>(options.ResourceAttributes),
148-
includedData: options.IncludedData);
178+
ILogEventSink? logsSink = null, tracesSink = null;
179+
180+
if (options.LogsEndpoint != null)
181+
{
182+
logsSink = new OpenTelemetryLogsSink(
183+
exporter: exporter,
184+
formatProvider: options.FormatProvider,
185+
resourceAttributes: new Dictionary<string, object>(options.ResourceAttributes),
186+
includedData: options.IncludedData);
187+
}
188+
189+
if (options.TracesEndpoint != null)
190+
{
191+
tracesSink = new OpenTelemetryTracesSink(
192+
exporter: exporter,
193+
resourceAttributes: new Dictionary<string, object>(options.ResourceAttributes),
194+
includedData: options.IncludedData);
195+
}
196+
197+
var sink = new OpenTelemetrySink(exporter, logsSink, tracesSink);
149198

150199
return loggerAuditSinkConfiguration.Sink(sink, options.RestrictedToMinimumLevel, options.LevelSwitch);
151200
}

0 commit comments

Comments
 (0)