Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the native Activity properties Status and StatusDescription #359

Merged
merged 4 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions src/OpenTelemetry.Exporter.Geneva/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@
* TraceExporter bug fix to not export non-recorded Activities.
[352](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/352)

* Add support for the native `Activity` properties `Status` and
`StatusDescription`.
[359](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/359)

## 1.2.6 [2022-Apr-21]

* Set GenevaMetricExporter temporality preference back to Delta.
[323](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/323)

## 1.2.5 [2022-Apr-20] Broken

Note: This release was broken due to the GenevaMetricExporter
using a TemporalityPreference of Cumulative instead of Delta, it has been
unlisted from NuGet.
Note: This release was broken due to the GenevaMetricExporter using a
TemporalityPreference of Cumulative instead of Delta, it has been unlisted from
NuGet.
[303](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/303)
is the PR that introduced this bug to GenevaMetricExporterExtensions.cs

Expand All @@ -26,20 +30,17 @@ is the PR that introduced this bug to GenevaMetricExporterExtensions.cs

## 1.2.4 [2022-Apr-20] Broken

This is the first release of the `OpenTelemetry.Exporter.Geneva`
project.
Note: This release was broken due to using OpenTelemetry 1.2.0-rc5.
Therefore, it has been unlisted on NuGet.
This is the first release of the `OpenTelemetry.Exporter.Geneva` project. Note:
This release was broken due to using OpenTelemetry 1.2.0-rc5. Therefore, it has
been unlisted on NuGet.

* LogExporter modified to stop calling `ToString()`
on `LogRecord.State` to obtain Log body. It now
obtains body from `LogRecord.FormattedMessage`
or special casing "{OriginalFormat}" only.
* LogExporter modified to stop calling `ToString()` on `LogRecord.State` to
obtain Log body. It now obtains body from `LogRecord.FormattedMessage` or
special casing "{OriginalFormat}" only.
[295](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/295)

* Fixed a bug which causes LogExporter to not
serialize if the `LogRecord.State` had a
single KeyValuePair.
* Fixed a bug which causes LogExporter to not serialize if the `LogRecord.State`
had a single KeyValuePair.
[295](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/295)

* Update OTel SDK version to `1.2.0-rc5`.
Expand Down
41 changes: 38 additions & 3 deletions src/OpenTelemetry.Exporter.Geneva/GenevaTraceExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ public GenevaTraceExporter(GenevaExporterOptions options)
}

dedicatedFields["otel.status_code"] = true;
dedicatedFields["otel.status_description"] = true;
this.m_dedicatedFields = dedicatedFields;
}

Expand Down Expand Up @@ -333,6 +334,9 @@ internal int SerializeActivity(Activity activity)
// Iteration #1 - Get those fields which become dedicated column
// i.e all PartB fields and opt-in part c fields.
bool hasEnvProperties = false;
bool isStatusSuccess = true;
string statusDescription = string.Empty;

foreach (var entry in activity.TagObjects)
{
// TODO: check name collision
Expand All @@ -344,11 +348,16 @@ internal int SerializeActivity(Activity activity)
{
if (string.Equals(entry.Value.ToString(), "ERROR", StringComparison.Ordinal))
{
MessagePackSerializer.SerializeBool(buffer, idxSuccessPatch, false);
isStatusSuccess = false;
}

continue;
}
else if (string.Equals(entry.Key, "otel.status_description", StringComparison.Ordinal))
{
statusDescription = entry.Value.ToString();
continue;
}
else if (this.m_customFields == null || this.m_customFields.ContainsKey(entry.Key))
{
// TODO: the above null check can be optimized and avoided inside foreach.
Expand Down Expand Up @@ -391,6 +400,34 @@ internal int SerializeActivity(Activity activity)
cntFields += 1;
MessagePackSerializer.WriteUInt16(buffer, idxMapSizeEnvPropertiesPatch, envPropertiesCount);
}

if (activity.Status != ActivityStatusCode.Unset)
{
if (activity.Status == ActivityStatusCode.Error)
{
MessagePackSerializer.SerializeBool(buffer, idxSuccessPatch, false);
}

if (!string.IsNullOrEmpty(activity.StatusDescription))
{
cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, "statusMessage");
cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, activity.StatusDescription);
cntFields += 1;
}
}
else
{
if (!isStatusSuccess)
{
MessagePackSerializer.SerializeBool(buffer, idxSuccessPatch, false);
if (!string.IsNullOrEmpty(statusDescription))
{
cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, "statusMessage");
cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, statusDescription);
cntFields += 1;
}
}
}
#endregion

MessagePackSerializer.WriteUInt16(buffer, this.m_idxMapSizePatch, cntFields);
Expand Down Expand Up @@ -436,8 +473,6 @@ internal int SerializeActivity(Activity activity)
["messaging.system"] = "messagingSystem",
["messaging.destination"] = "messagingDestination",
["messaging.url"] = "messagingUrl",

["otel.status_description"] = "statusMessage",
};

private bool isDisposed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,16 @@ public void GenevaTraceExporter_Serialization_Success(bool hasTableNameMapping,
activity?.SetTag("clientRequestId", "58a37988-2c05-427a-891f-5e0e1266fcc5");
activity?.SetTag("foo", 1);
activity?.SetTag("bar", 2);
activity?.SetStatus(Status.Error);
activity?.SetStatus(Status.Error.WithDescription("Error description from OTel API"));
}
}

Assert.Equal(2, invocationCount);
using (var activity = source.StartActivity("TestActivityForSetStatusAPI"))
{
activity?.SetStatus(ActivityStatusCode.Error, "Error description from .NET API");
}

Assert.Equal(3, invocationCount);
}
finally
{
Expand Down Expand Up @@ -461,7 +466,22 @@ private void AssertFluentdForwardModeForActivity(GenevaExporterOptions exporterO
Assert.Equal(activity.StartTimeUtc, mapping["startTime"]);

var activityStatusCode = activity.GetStatus().StatusCode;
Assert.Equal(activityStatusCode == StatusCode.Error ? false : true, mapping["success"]);

if (activity.Status == ActivityStatusCode.Error)
{
Assert.False((bool)mapping["success"]);
Assert.Equal(activity.StatusDescription, mapping["statusMessage"]);
}
else if (activityStatusCode == StatusCode.Error)
{
Assert.False((bool)mapping["success"]);
var activityStatusDesc = activity.GetStatus().Description;
Assert.Equal(activityStatusDesc, mapping["statusMessage"]);
}
else
{
Assert.True((bool)mapping["success"]);
}

// Part B Span optional fields and Part C fields
if (activity.ParentSpanId != default)
Expand Down Expand Up @@ -509,6 +529,11 @@ private void AssertFluentdForwardModeForActivity(GenevaExporterOptions exporterO
// Status code check is already done when we check for "success" key in the mapping
continue;
}
else if (string.Equals(tag.Key, "otel.status_description", StringComparison.Ordinal))
{
// Status description check is already done when we check for "statusMessage" key in the mapping
continue;
}
else
{
// If CustomFields are proivded, dedicatedFields will be populated
Expand Down