Skip to content

Commit

Permalink
[Exporter.Geneva] Update scopes (#736)
Browse files Browse the repository at this point in the history
* Update scopes
  • Loading branch information
utpilla authored Oct 28, 2022
1 parent 7099b6f commit 126cc34
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 55 deletions.
9 changes: 9 additions & 0 deletions src/OpenTelemetry.Exporter.Geneva/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Unreleased

* Breaking change: Updated export logic for scopes
* Export scopes which have a non-null key as individual columns (each
key-value pair from the scopes is exported as its own column; these columns
would also be taken into consideration when the CustomFields option is
applied).
* When using formatted strings for scopes, the templated string (`"{OriginalFormat"}`)
will not be exported.
[#736](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/736)

## 1.4.0-beta.3

Released 2022-Oct-20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,42 +349,31 @@ internal int SerializeLogRecord(LogRecord logRecord)
cntFields += 1;
}

ushort scopeDepth = 0;
int indexArrayLength = 0;
logRecord.ForEachScope(ProcessScope, (object)null);
void ProcessScope(LogRecordScope scope, object state)
logRecord.ForEachScope(ProcessScopeForIndividualColumns, (object)null);
void ProcessScopeForIndividualColumns(LogRecordScope scope, object state)
{
if (++scopeDepth == 1)
{
cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, "scopes");
cursor = MessagePackSerializer.WriteArrayHeader(buffer, cursor, ushort.MaxValue);
indexArrayLength = cursor - 2;
}

cursor = MessagePackSerializer.WriteMapHeader(buffer, cursor, ushort.MaxValue);
int indexMapSizeScope = cursor - 2;
ushort keysCount = 0;

foreach (KeyValuePair<string, object> scopeItem in scope)
{
string key = "scope";
if (!string.IsNullOrEmpty(scopeItem.Key))
if (string.IsNullOrEmpty(scopeItem.Key) || scopeItem.Key == "{OriginalFormat}")
{
key = scopeItem.Key;
continue;
}

cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, key);
cursor = MessagePackSerializer.Serialize(buffer, cursor, scopeItem.Value);
keysCount++;
if (this.m_customFields == null || this.m_customFields.ContainsKey(scopeItem.Key))
{
if (scopeItem.Value != null)
{
// null is not supported.
cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, scopeItem.Key);
cursor = MessagePackSerializer.Serialize(buffer, cursor, scopeItem.Value);
cntFields += 1;
}
}
else
{
hasEnvProperties = true;
}
}

MessagePackSerializer.WriteUInt16(buffer, indexMapSizeScope, keysCount);
}

if (scopeDepth > 0)
{
MessagePackSerializer.WriteUInt16(buffer, indexArrayLength, scopeDepth);
cntFields += 1;
}

if (hasEnvProperties)
Expand All @@ -410,6 +399,25 @@ void ProcessScope(LogRecordScope scope, object state)
}
}

logRecord.ForEachScope(ProcessScopeForEnvProperties, (object)null);
void ProcessScopeForEnvProperties(LogRecordScope scope, object state)
{
foreach (KeyValuePair<string, object> scopeItem in scope)
{
if (string.IsNullOrEmpty(scopeItem.Key) || scopeItem.Key == "{OriginalFormat}")
{
continue;
}

if (!this.m_customFields.ContainsKey(scopeItem.Key))
{
cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, scopeItem.Key);
cursor = MessagePackSerializer.Serialize(buffer, cursor, scopeItem.Value);
envPropertiesCount += 1;
}
}
}

cntFields += 1;
MessagePackSerializer.WriteUInt16(buffer, idxMapSizeEnvPropertiesPatch, envPropertiesCount);
}
Expand Down
39 changes: 13 additions & 26 deletions test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,13 @@ public void SerializeILoggerScopes()
senderSocket.Listen(1);
}

var exportedItems = new List<LogRecord>();

using var loggerFactory = LoggerFactory.Create(builder => builder
.AddOpenTelemetry(options =>
{
options.IncludeScopes = true;
options.AddInMemoryExporter(exportedItems);
options.AddGenevaLogExporter(options =>
{
options.ConnectionString = exporterOptions.ConnectionString;
Expand All @@ -405,7 +408,7 @@ public void SerializeILoggerScopes()

using (logger.BeginScope("MyOuterScope"))
using (logger.BeginScope("MyInnerScope"))
using (logger.BeginScope("MyInnerInnerScope with {name} and {age} of custom", "John Doe", 35))
using (logger.BeginScope("MyInnerInnerScope with {Name} and {Age} of custom", "John Doe", 35))
using (logger.BeginScope(new List<KeyValuePair<string, object>> { new KeyValuePair<string, object>("MyKey", "MyValue") }))
{
logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99);
Expand All @@ -428,31 +431,15 @@ public void SerializeILoggerScopes()
var signal = (fluentdData as object[])[0] as string;
var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0];
var mapping = (TimeStampAndMappings as object[])[1] as Dictionary<object, object>;
var serializedScopes = mapping["scopes"] as object[];

Assert.Equal(4, serializedScopes.Length);

// Test 1st scope
var scope = serializedScopes[0] as ICollection<KeyValuePair<object, object>>;
Assert.Single(scope);
Assert.Contains(new KeyValuePair<object, object>("scope", "MyOuterScope"), scope);

// Test 2nd scope
scope = serializedScopes[1] as ICollection<KeyValuePair<object, object>>;
Assert.Single(scope);
Assert.Contains(new KeyValuePair<object, object>("scope", "MyInnerScope"), scope);

// Test 3rd scope
scope = serializedScopes[2] as ICollection<KeyValuePair<object, object>>;
Assert.Equal(3, scope.Count);
Assert.Contains(new KeyValuePair<object, object>("name", "John Doe"), scope);
Assert.Contains(new KeyValuePair<object, object>("age", (byte)35), scope);
Assert.Contains(new KeyValuePair<object, object>("{OriginalFormat}", "MyInnerInnerScope with {name} and {age} of custom"), scope);

// Test 4th scope
scope = serializedScopes[3] as ICollection<KeyValuePair<object, object>>;
Assert.Single(scope);
Assert.Contains(new KeyValuePair<object, object>("MyKey", "MyValue"), scope);
Assert.Equal("John Doe", mapping["Name"]);
Assert.Equal((byte)35, mapping["Age"]);
Assert.Equal("MyValue", mapping["MyKey"]);

// Check other fields
Assert.Single(exportedItems);
var logRecord = exportedItems[0];

this.AssertFluentdForwardModeForLogRecord(exporterOptions, fluentdData, logRecord);
}
finally
{
Expand Down

0 comments on commit 126cc34

Please sign in to comment.