opentelemetry-dotnet icon indicating copy to clipboard operation
opentelemetry-dotnet copied to clipboard

[logs] Potential data loss when using custom log enrichment processor and upgrading to v1.5.0 - v1.7.0

Open CodeBlanch opened this issue 1 year ago • 0 comments

[This issue is a meant as a landing spot for anyone searching.]

Issue: When upgrading to OpenTelemetry.dll v1.5.0 - v1.7.0 users may lose attributes added by custom LogRecord processors

Who is impacted?

Users attempting to enrich LogRecord instances via a BaseProcessor<LogRecord> implementation by setting only LogRecord.State. For example:

private sealed class LogEnrichmentProcessor : BaseProcessor<LogRecord>
{
    public override void OnEnd(LogRecord data)
    {
        if (data.State is IReadOnlyList<KeyValuePair<string, object?>> listOfKvp)
        {
            data.State = this.AddFields(listOfKvp);
        }
    }

    private IReadOnlyList<KeyValuePair<string, object?>> AddFields(IReadOnlyList<KeyValuePair<string, object?>> stateValues)
    {
        // Implementation not shown
    }
}

What happens?

Starting with OpenTelemetry v1.5.0 the SDK will automatically set Attributes \ StateValues if the logged TState implements IReadOnlyList or IEnumerable of KeyValuePair<string, object?>.

When the OnEnd code above executes, LogRecord.State & LogRecord.Attributes \ LogRecord.StateValues are in sync. But when it exits, they are out of sync.

Depending on the exporter(s) being used, data loss may occur:

  • If an exporter looks at Attributes \ StateValues first, it will export the original (prior to enrichment) attributes and the enriched attributes will be lost.

  • If an exporter looks at State first, everything should work fine and the enriched data will be exported.

Is there a fix?

  • Upgrade to an OpenTelemetry SDK >v1.7.0 which includes #5169 to keep State & Attributes \ StateValues in sync automatically.

  • Or update the log processor to do this:

         public override void OnEnd(LogRecord data)
         {
              if (data.State is IReadOnlyList<KeyValuePair<string, object>> listOfKvp)
              {
                  data.State = data.StateValues = this.AddFields(data, listOfKvp);
              }
         }
    

    Setting both State and StateValues (or Attributes) will work for all known SDK versions.

CodeBlanch avatar Dec 15 '23 20:12 CodeBlanch