Skip to content

Commit

Permalink
Fix severity mapping for OTLP Log Exporter (#3177)
Browse files Browse the repository at this point in the history
  • Loading branch information
cijothomas authored Apr 14, 2022
1 parent 4ff7278 commit a9d15c0
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* LogExporter to correcly map Severity to OTLP.
([#3177](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3177))

## 1.2.0-rc5

Released 2022-Apr-12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Runtime.CompilerServices;
using Google.Protobuf;
using Google.Protobuf.Collections;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Internal;
using OpenTelemetry.Logs;
using OpenTelemetry.Trace;
Expand All @@ -30,12 +31,17 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation
{
internal static class LogRecordExtensions
{
private static readonly string[] LogLevels = new string[7]
{
"Trace", "Debug", "Information", "Warning", "Error", "Critical", "None",
};

internal static void AddBatch(
this OtlpCollector.ExportLogsServiceRequest request,
OtlpResource.Resource processResource,
in Batch<LogRecord> logRecordBatch)
{
OtlpLogs.ResourceLogs resourceLogs = new OtlpLogs.ResourceLogs
var resourceLogs = new OtlpLogs.ResourceLogs
{
Resource = processResource,
};
Expand Down Expand Up @@ -64,10 +70,8 @@ internal static OtlpLogs.LogRecord ToOtlpLog(this LogRecord logRecord)
otlpLogRecord = new OtlpLogs.LogRecord
{
TimeUnixNano = (ulong)logRecord.Timestamp.ToUnixTimeNanoseconds(),

// TODO: Devise mapping of LogLevel to SeverityNumber
// See: https://github.com/open-telemetry/opentelemetry-proto/blob/bacfe08d84e21fb2a779e302d12e8dfeb67e7b86/opentelemetry/proto/logs/v1/logs.proto#L100-L102
SeverityText = logRecord.LogLevel.ToString(),
SeverityNumber = GetSeverityNumber(logRecord.LogLevel),
SeverityText = LogLevels[(int)logRecord.LogLevel],
};

// TODO: Add logRecord.CategoryName as an attribute
Expand Down Expand Up @@ -144,5 +148,37 @@ private static void AddIntAttribute(this RepeatedField<OtlpCommon.KeyValue> repe
Value = new OtlpCommon.AnyValue { IntValue = value },
});
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static OtlpLogs.SeverityNumber GetSeverityNumber(LogLevel logLevel)
{
// Maps the ILogger LogLevel to OpenTelemetry logging level.
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#appendix-b-severitynumber-example-mappings
// TODO: for improving perf simply do ((int)loglevel * 4) + 1
// or ((int)logLevel << 2) + 1
// Current code is just for ease of reading.
switch (logLevel)
{
case LogLevel.Trace:
return OtlpLogs.SeverityNumber.Trace;
case LogLevel.Debug:
return OtlpLogs.SeverityNumber.Debug;
case LogLevel.Information:
return OtlpLogs.SeverityNumber.Info;
case LogLevel.Warning:
return OtlpLogs.SeverityNumber.Warn;
case LogLevel.Error:
return OtlpLogs.SeverityNumber.Error;
case LogLevel.Critical:
return OtlpLogs.SeverityNumber.Fatal;

// TODO:
// we reach default only for LogLevel.None
// but that is filtered out anyway.
// should we throw here then?
default:
return OtlpLogs.SeverityNumber.Debug;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using OpenTelemetry.Tests;
using OpenTelemetry.Trace;
using Xunit;
using OtlpLogs = Opentelemetry.Proto.Logs.V1;

namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests
{
Expand All @@ -32,7 +33,7 @@ public class OtlpLogExporterTests : Http2UnencryptedSupportTests
[Fact]
public void CheckToOtlpLogRecordStateValues()
{
List<LogRecord> logRecords = new List<LogRecord>();
var logRecords = new List<LogRecord>();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options =>
Expand Down Expand Up @@ -61,7 +62,7 @@ public void CheckToOtlpLogRecordStateValues()
[Fact]
public void CheckToOtlpLogRecordEventId()
{
List<LogRecord> logRecords = new List<LogRecord>();
var logRecords = new List<LogRecord>();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options =>
Expand Down Expand Up @@ -110,7 +111,7 @@ public void CheckToOtlpLogRecordEventId()
[Fact]
public void CheckToOtlpLogRecordTraceIdSpanIdFlagWithNoActivity()
{
List<LogRecord> logRecords = new List<LogRecord>();
var logRecords = new List<LogRecord>();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options =>
Expand All @@ -133,7 +134,7 @@ public void CheckToOtlpLogRecordTraceIdSpanIdFlagWithNoActivity()
[Fact]
public void CheckToOtlpLogRecordSpanIdTraceIdAndFlag()
{
List<LogRecord> logRecords = new List<LogRecord>();
var logRecords = new List<LogRecord>();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options =>
Expand Down Expand Up @@ -162,34 +163,62 @@ public void CheckToOtlpLogRecordSpanIdTraceIdAndFlag()
Assert.Equal((uint)logRecord.TraceFlags, otlpLogRecord.Flags);
}

[Fact]
public void CheckToOtlpLogRecordSeverityText()
[Theory]
[InlineData(LogLevel.Trace)]
[InlineData(LogLevel.Debug)]
[InlineData(LogLevel.Information)]
[InlineData(LogLevel.Warning)]
[InlineData(LogLevel.Error)]
[InlineData(LogLevel.Critical)]
public void CheckToOtlpLogRecordSeverityLevelAndText(LogLevel logLevel)
{
List<LogRecord> logRecords = new List<LogRecord>();
var logRecords = new List<LogRecord>();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options =>
{
options.AddInMemoryExporter(logRecords);
options.IncludeFormattedMessage = true;
});
})
.AddFilter("CheckToOtlpLogRecordSeverityLevelAndText", LogLevel.Trace);
});

var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
var logger = loggerFactory.CreateLogger("CheckToOtlpLogRecordSeverityLevelAndText");
logger.Log(logLevel, "Hello from {name} {price}.", "tomato", 2.99);
Assert.Single(logRecords);

var logRecord = logRecords[0];
var otlpLogRecord = logRecord.ToOtlpLog();

Assert.NotNull(otlpLogRecord);
Assert.Equal(logRecord.LogLevel.ToString(), otlpLogRecord.SeverityText);
switch (logLevel)
{
case LogLevel.Trace:
Assert.Equal(OtlpLogs.SeverityNumber.Trace, otlpLogRecord.SeverityNumber);
break;
case LogLevel.Debug:
Assert.Equal(OtlpLogs.SeverityNumber.Debug, otlpLogRecord.SeverityNumber);
break;
case LogLevel.Information:
Assert.Equal(OtlpLogs.SeverityNumber.Info, otlpLogRecord.SeverityNumber);
break;
case LogLevel.Warning:
Assert.Equal(OtlpLogs.SeverityNumber.Warn, otlpLogRecord.SeverityNumber);
break;
case LogLevel.Error:
Assert.Equal(OtlpLogs.SeverityNumber.Error, otlpLogRecord.SeverityNumber);
break;
case LogLevel.Critical:
Assert.Equal(OtlpLogs.SeverityNumber.Fatal, otlpLogRecord.SeverityNumber);
break;
}
}

[Fact]
public void CheckToOtlpLogRecordFormattedMessage()
{
List<LogRecord> logRecords = new List<LogRecord>();
var logRecords = new List<LogRecord>();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options =>
Expand All @@ -213,7 +242,7 @@ public void CheckToOtlpLogRecordFormattedMessage()
[Fact]
public void CheckToOtlpLogRecordExceptionAttributes()
{
List<LogRecord> logRecords = new List<LogRecord>();
var logRecords = new List<LogRecord>();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options =>
Expand Down

0 comments on commit a9d15c0

Please sign in to comment.