| File: Otlp\Model\Serialization\OtlpJsonProtobufConverter.cs | Web Access |
| Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Otlp.Serialization; using Google.Protobuf; using OpenTelemetry.Proto.Collector.Logs.V1; using OpenTelemetry.Proto.Collector.Metrics.V1; using OpenTelemetry.Proto.Collector.Trace.V1; using OpenTelemetry.Proto.Common.V1; using OpenTelemetry.Proto.Logs.V1; using OpenTelemetry.Proto.Metrics.V1; using OpenTelemetry.Proto.Resource.V1; using OpenTelemetry.Proto.Trace.V1; namespace Aspire.Dashboard.Otlp.Model.Serialization; /// <summary> /// Converts OTLP JSON types to protobuf types. /// </summary> internal static class OtlpJsonToProtobufConverter { /// <summary> /// Converts an export trace service request from JSON to protobuf. /// </summary> public static ExportTraceServiceRequest ToProtobuf(OtlpExportTraceServiceRequestJson json) { var request = new ExportTraceServiceRequest(); if (json.ResourceSpans is not null) { foreach (var rs in json.ResourceSpans) { request.ResourceSpans.Add(ToProtobuf(rs)); } } return request; } /// <summary> /// Converts an export logs service request from JSON to protobuf. /// </summary> public static ExportLogsServiceRequest ToProtobuf(OtlpExportLogsServiceRequestJson json) { var request = new ExportLogsServiceRequest(); if (json.ResourceLogs is not null) { foreach (var rl in json.ResourceLogs) { request.ResourceLogs.Add(ToProtobuf(rl)); } } return request; } /// <summary> /// Converts an export metrics service request from JSON to protobuf. /// </summary> public static ExportMetricsServiceRequest ToProtobuf(OtlpExportMetricsServiceRequestJson json) { var request = new ExportMetricsServiceRequest(); if (json.ResourceMetrics is not null) { foreach (var rm in json.ResourceMetrics) { request.ResourceMetrics.Add(ToProtobuf(rm)); } } return request; } private static ResourceSpans ToProtobuf(OtlpResourceSpansJson json) { var resourceSpans = new ResourceSpans(); if (json.Resource is not null) { resourceSpans.Resource = ToProtobuf(json.Resource); } if (json.ScopeSpans is not null) { foreach (var ss in json.ScopeSpans) { resourceSpans.ScopeSpans.Add(ToProtobuf(ss)); } } if (json.SchemaUrl is not null) { resourceSpans.SchemaUrl = json.SchemaUrl; } return resourceSpans; } private static ScopeSpans ToProtobuf(OtlpScopeSpansJson json) { var scopeSpans = new ScopeSpans(); if (json.Scope is not null) { scopeSpans.Scope = ToProtobuf(json.Scope); } if (json.Spans is not null) { foreach (var s in json.Spans) { scopeSpans.Spans.Add(ToProtobuf(s)); } } if (json.SchemaUrl is not null) { scopeSpans.SchemaUrl = json.SchemaUrl; } return scopeSpans; } private static Span ToProtobuf(OtlpSpanJson json) { var span = new Span(); if (json.TraceId is not null) { span.TraceId = HexToByteString(json.TraceId); } if (json.SpanId is not null) { span.SpanId = HexToByteString(json.SpanId); } if (json.TraceState is not null) { span.TraceState = json.TraceState; } if (json.ParentSpanId is not null) { span.ParentSpanId = HexToByteString(json.ParentSpanId); } if (json.Flags.HasValue) { span.Flags = json.Flags.Value; } if (json.Name is not null) { span.Name = json.Name; } if (json.Kind.HasValue) { span.Kind = (Span.Types.SpanKind)json.Kind.Value; } if (json.StartTimeUnixNano.HasValue) { span.StartTimeUnixNano = json.StartTimeUnixNano.Value; } if (json.EndTimeUnixNano.HasValue) { span.EndTimeUnixNano = json.EndTimeUnixNano.Value; } if (json.Attributes is not null) { foreach (var attr in json.Attributes) { span.Attributes.Add(ToProtobuf(attr)); } } span.DroppedAttributesCount = json.DroppedAttributesCount; if (json.Events is not null) { foreach (var evt in json.Events) { span.Events.Add(ToProtobuf(evt)); } } span.DroppedEventsCount = json.DroppedEventsCount; if (json.Links is not null) { foreach (var link in json.Links) { span.Links.Add(ToProtobuf(link)); } } span.DroppedLinksCount = json.DroppedLinksCount; if (json.Status is not null) { span.Status = ToProtobuf(json.Status); } return span; } private static Span.Types.Event ToProtobuf(OtlpSpanEventJson json) { var evt = new Span.Types.Event(); if (json.TimeUnixNano.HasValue) { evt.TimeUnixNano = json.TimeUnixNano.Value; } if (json.Name is not null) { evt.Name = json.Name; } if (json.Attributes is not null) { foreach (var attr in json.Attributes) { evt.Attributes.Add(ToProtobuf(attr)); } } evt.DroppedAttributesCount = json.DroppedAttributesCount; return evt; } private static Span.Types.Link ToProtobuf(OtlpSpanLinkJson json) { var link = new Span.Types.Link(); if (json.TraceId is not null) { link.TraceId = HexToByteString(json.TraceId); } if (json.SpanId is not null) { link.SpanId = HexToByteString(json.SpanId); } if (json.TraceState is not null) { link.TraceState = json.TraceState; } if (json.Attributes is not null) { foreach (var attr in json.Attributes) { link.Attributes.Add(ToProtobuf(attr)); } } link.DroppedAttributesCount = json.DroppedAttributesCount; if (json.Flags.HasValue) { link.Flags = json.Flags.Value; } return link; } private static Status ToProtobuf(OtlpSpanStatusJson json) { var status = new Status(); if (json.Message is not null) { status.Message = json.Message; } if (json.Code.HasValue) { status.Code = (Status.Types.StatusCode)json.Code.Value; } return status; } private static ResourceLogs ToProtobuf(OtlpResourceLogsJson json) { var resourceLogs = new ResourceLogs(); if (json.Resource is not null) { resourceLogs.Resource = ToProtobuf(json.Resource); } if (json.ScopeLogs is not null) { foreach (var sl in json.ScopeLogs) { resourceLogs.ScopeLogs.Add(ToProtobuf(sl)); } } if (json.SchemaUrl is not null) { resourceLogs.SchemaUrl = json.SchemaUrl; } return resourceLogs; } private static ScopeLogs ToProtobuf(OtlpScopeLogsJson json) { var scopeLogs = new ScopeLogs(); if (json.Scope is not null) { scopeLogs.Scope = ToProtobuf(json.Scope); } if (json.LogRecords is not null) { foreach (var lr in json.LogRecords) { scopeLogs.LogRecords.Add(ToProtobuf(lr)); } } if (json.SchemaUrl is not null) { scopeLogs.SchemaUrl = json.SchemaUrl; } return scopeLogs; } private static LogRecord ToProtobuf(OtlpLogRecordJson json) { var logRecord = new LogRecord(); if (json.TimeUnixNano.HasValue) { logRecord.TimeUnixNano = json.TimeUnixNano.Value; } if (json.ObservedTimeUnixNano.HasValue) { logRecord.ObservedTimeUnixNano = json.ObservedTimeUnixNano.Value; } if (json.SeverityNumber.HasValue) { logRecord.SeverityNumber = (SeverityNumber)json.SeverityNumber.Value; } if (json.SeverityText is not null) { logRecord.SeverityText = json.SeverityText; } if (json.Body is not null) { logRecord.Body = ToProtobuf(json.Body); } if (json.Attributes is not null) { foreach (var attr in json.Attributes) { logRecord.Attributes.Add(ToProtobuf(attr)); } } logRecord.DroppedAttributesCount = json.DroppedAttributesCount; logRecord.Flags = json.Flags; if (json.TraceId is not null) { logRecord.TraceId = HexToByteString(json.TraceId); } if (json.SpanId is not null) { logRecord.SpanId = HexToByteString(json.SpanId); } if (json.EventName is not null) { logRecord.EventName = json.EventName; } return logRecord; } private static ResourceMetrics ToProtobuf(OtlpResourceMetricsJson json) { var resourceMetrics = new ResourceMetrics(); if (json.Resource is not null) { resourceMetrics.Resource = ToProtobuf(json.Resource); } if (json.ScopeMetrics is not null) { foreach (var sm in json.ScopeMetrics) { resourceMetrics.ScopeMetrics.Add(ToProtobuf(sm)); } } if (json.SchemaUrl is not null) { resourceMetrics.SchemaUrl = json.SchemaUrl; } return resourceMetrics; } private static ScopeMetrics ToProtobuf(OtlpScopeMetricsJson json) { var scopeMetrics = new ScopeMetrics(); if (json.Scope is not null) { scopeMetrics.Scope = ToProtobuf(json.Scope); } if (json.Metrics is not null) { foreach (var m in json.Metrics) { scopeMetrics.Metrics.Add(ToProtobuf(m)); } } if (json.SchemaUrl is not null) { scopeMetrics.SchemaUrl = json.SchemaUrl; } return scopeMetrics; } private static Metric ToProtobuf(OtlpMetricJson json) { var metric = new Metric(); if (json.Name is not null) { metric.Name = json.Name; } if (json.Description is not null) { metric.Description = json.Description; } if (json.Unit is not null) { metric.Unit = json.Unit; } if (json.Gauge is not null) { metric.Gauge = ToProtobuf(json.Gauge); } else if (json.Sum is not null) { metric.Sum = ToProtobuf(json.Sum); } else if (json.Histogram is not null) { metric.Histogram = ToProtobuf(json.Histogram); } else if (json.ExponentialHistogram is not null) { metric.ExponentialHistogram = ToProtobuf(json.ExponentialHistogram); } else if (json.Summary is not null) { metric.Summary = ToProtobuf(json.Summary); } if (json.Metadata is not null) { foreach (var kv in json.Metadata) { metric.Metadata.Add(ToProtobuf(kv)); } } return metric; } private static Gauge ToProtobuf(OtlpGaugeJson json) { var gauge = new Gauge(); if (json.DataPoints is not null) { foreach (var dp in json.DataPoints) { gauge.DataPoints.Add(ToProtobuf(dp)); } } return gauge; } private static Sum ToProtobuf(OtlpSumJson json) { var sum = new Sum(); if (json.DataPoints is not null) { foreach (var dp in json.DataPoints) { sum.DataPoints.Add(ToProtobuf(dp)); } } if (json.AggregationTemporality.HasValue) { sum.AggregationTemporality = (AggregationTemporality)json.AggregationTemporality.Value; } sum.IsMonotonic = json.IsMonotonic; return sum; } private static Histogram ToProtobuf(OtlpHistogramJson json) { var histogram = new Histogram(); if (json.DataPoints is not null) { foreach (var dp in json.DataPoints) { histogram.DataPoints.Add(ToProtobuf(dp)); } } if (json.AggregationTemporality.HasValue) { histogram.AggregationTemporality = (AggregationTemporality)json.AggregationTemporality.Value; } return histogram; } private static ExponentialHistogram ToProtobuf(OtlpExponentialHistogramJson json) { var histogram = new ExponentialHistogram(); if (json.DataPoints is not null) { foreach (var dp in json.DataPoints) { histogram.DataPoints.Add(ToProtobuf(dp)); } } if (json.AggregationTemporality.HasValue) { histogram.AggregationTemporality = (AggregationTemporality)json.AggregationTemporality.Value; } return histogram; } private static Summary ToProtobuf(OtlpSummaryJson json) { var summary = new Summary(); if (json.DataPoints is not null) { foreach (var dp in json.DataPoints) { summary.DataPoints.Add(ToProtobuf(dp)); } } return summary; } private static NumberDataPoint ToProtobuf(OtlpNumberDataPointJson json) { var dataPoint = new NumberDataPoint(); if (json.Attributes is not null) { foreach (var attr in json.Attributes) { dataPoint.Attributes.Add(ToProtobuf(attr)); } } if (json.StartTimeUnixNano.HasValue) { dataPoint.StartTimeUnixNano = json.StartTimeUnixNano.Value; } if (json.TimeUnixNano.HasValue) { dataPoint.TimeUnixNano = json.TimeUnixNano.Value; } if (json.AsDouble.HasValue) { dataPoint.AsDouble = json.AsDouble.Value; } else if (json.AsInt.HasValue) { dataPoint.AsInt = json.AsInt.Value; } if (json.Exemplars is not null) { foreach (var ex in json.Exemplars) { dataPoint.Exemplars.Add(ToProtobuf(ex)); } } dataPoint.Flags = json.Flags; return dataPoint; } private static HistogramDataPoint ToProtobuf(OtlpHistogramDataPointJson json) { var dataPoint = new HistogramDataPoint(); if (json.Attributes is not null) { foreach (var attr in json.Attributes) { dataPoint.Attributes.Add(ToProtobuf(attr)); } } if (json.StartTimeUnixNano.HasValue) { dataPoint.StartTimeUnixNano = json.StartTimeUnixNano.Value; } if (json.TimeUnixNano.HasValue) { dataPoint.TimeUnixNano = json.TimeUnixNano.Value; } if (json.Count.HasValue) { dataPoint.Count = json.Count.Value; } if (json.Sum.HasValue) { dataPoint.Sum = json.Sum.Value; } if (json.BucketCounts is not null) { foreach (var bc in json.BucketCounts) { dataPoint.BucketCounts.Add(ulong.Parse(bc, System.Globalization.CultureInfo.InvariantCulture)); } } if (json.ExplicitBounds is not null) { foreach (var eb in json.ExplicitBounds) { dataPoint.ExplicitBounds.Add(eb); } } if (json.Exemplars is not null) { foreach (var ex in json.Exemplars) { dataPoint.Exemplars.Add(ToProtobuf(ex)); } } dataPoint.Flags = json.Flags; if (json.Min.HasValue) { dataPoint.Min = json.Min.Value; } if (json.Max.HasValue) { dataPoint.Max = json.Max.Value; } return dataPoint; } private static ExponentialHistogramDataPoint ToProtobuf(OtlpExponentialHistogramDataPointJson json) { var dataPoint = new ExponentialHistogramDataPoint(); if (json.Attributes is not null) { foreach (var attr in json.Attributes) { dataPoint.Attributes.Add(ToProtobuf(attr)); } } if (json.StartTimeUnixNano.HasValue) { dataPoint.StartTimeUnixNano = json.StartTimeUnixNano.Value; } if (json.TimeUnixNano.HasValue) { dataPoint.TimeUnixNano = json.TimeUnixNano.Value; } if (json.Count.HasValue) { dataPoint.Count = json.Count.Value; } if (json.Sum.HasValue) { dataPoint.Sum = json.Sum.Value; } dataPoint.Scale = json.Scale; if (json.ZeroCount.HasValue) { dataPoint.ZeroCount = json.ZeroCount.Value; } if (json.Positive is not null) { dataPoint.Positive = ToProtobuf(json.Positive); } if (json.Negative is not null) { dataPoint.Negative = ToProtobuf(json.Negative); } dataPoint.Flags = json.Flags; if (json.Exemplars is not null) { foreach (var ex in json.Exemplars) { dataPoint.Exemplars.Add(ToProtobuf(ex)); } } if (json.Min.HasValue) { dataPoint.Min = json.Min.Value; } if (json.Max.HasValue) { dataPoint.Max = json.Max.Value; } dataPoint.ZeroThreshold = json.ZeroThreshold; return dataPoint; } private static ExponentialHistogramDataPoint.Types.Buckets ToProtobuf(OtlpExponentialHistogramBucketsJson json) { var buckets = new ExponentialHistogramDataPoint.Types.Buckets(); buckets.Offset = json.Offset; if (json.BucketCounts is not null) { foreach (var bc in json.BucketCounts) { buckets.BucketCounts.Add(ulong.Parse(bc, System.Globalization.CultureInfo.InvariantCulture)); } } return buckets; } private static SummaryDataPoint ToProtobuf(OtlpSummaryDataPointJson json) { var dataPoint = new SummaryDataPoint(); if (json.Attributes is not null) { foreach (var attr in json.Attributes) { dataPoint.Attributes.Add(ToProtobuf(attr)); } } if (json.StartTimeUnixNano.HasValue) { dataPoint.StartTimeUnixNano = json.StartTimeUnixNano.Value; } if (json.TimeUnixNano.HasValue) { dataPoint.TimeUnixNano = json.TimeUnixNano.Value; } if (json.Count.HasValue) { dataPoint.Count = json.Count.Value; } dataPoint.Sum = json.Sum; if (json.QuantileValues is not null) { foreach (var qv in json.QuantileValues) { dataPoint.QuantileValues.Add(ToProtobuf(qv)); } } dataPoint.Flags = json.Flags; return dataPoint; } private static SummaryDataPoint.Types.ValueAtQuantile ToProtobuf(OtlpValueAtQuantileJson json) { var valueAtQuantile = new SummaryDataPoint.Types.ValueAtQuantile(); valueAtQuantile.Quantile = json.Quantile; valueAtQuantile.Value = json.Value; return valueAtQuantile; } private static Exemplar ToProtobuf(OtlpExemplarJson json) { var exemplar = new Exemplar(); if (json.FilteredAttributes is not null) { foreach (var attr in json.FilteredAttributes) { exemplar.FilteredAttributes.Add(ToProtobuf(attr)); } } if (json.TimeUnixNano.HasValue) { exemplar.TimeUnixNano = json.TimeUnixNano.Value; } if (json.AsDouble.HasValue) { exemplar.AsDouble = json.AsDouble.Value; } else if (json.AsInt.HasValue) { exemplar.AsInt = json.AsInt.Value; } if (json.SpanId is not null) { exemplar.SpanId = HexToByteString(json.SpanId); } if (json.TraceId is not null) { exemplar.TraceId = HexToByteString(json.TraceId); } return exemplar; } private static Resource ToProtobuf(OtlpResourceJson json) { var resource = new Resource(); if (json.Attributes is not null) { foreach (var attr in json.Attributes) { resource.Attributes.Add(ToProtobuf(attr)); } } resource.DroppedAttributesCount = json.DroppedAttributesCount; return resource; } private static InstrumentationScope ToProtobuf(OtlpInstrumentationScopeJson json) { var scope = new InstrumentationScope(); if (json.Name is not null) { scope.Name = json.Name; } if (json.Version is not null) { scope.Version = json.Version; } if (json.Attributes is not null) { foreach (var attr in json.Attributes) { scope.Attributes.Add(ToProtobuf(attr)); } } scope.DroppedAttributesCount = json.DroppedAttributesCount; return scope; } private static KeyValue ToProtobuf(OtlpKeyValueJson json) { var kv = new KeyValue(); if (json.Key is not null) { kv.Key = json.Key; } if (json.Value is not null) { kv.Value = ToProtobuf(json.Value); } return kv; } private static AnyValue ToProtobuf(OtlpAnyValueJson json) { var anyValue = new AnyValue(); if (json.StringValue is not null) { anyValue.StringValue = json.StringValue; } else if (json.BoolValue.HasValue) { anyValue.BoolValue = json.BoolValue.Value; } else if (json.IntValue.HasValue) { anyValue.IntValue = json.IntValue.Value; } else if (json.DoubleValue.HasValue) { anyValue.DoubleValue = json.DoubleValue.Value; } else if (json.ArrayValue is not null) { anyValue.ArrayValue = ToProtobuf(json.ArrayValue); } else if (json.KvlistValue is not null) { anyValue.KvlistValue = ToProtobuf(json.KvlistValue); } else if (json.BytesValue is not null) { anyValue.BytesValue = ByteString.FromBase64(json.BytesValue); } return anyValue; } private static ArrayValue ToProtobuf(OtlpArrayValueJson json) { var arrayValue = new ArrayValue(); if (json.Values is not null) { foreach (var v in json.Values) { arrayValue.Values.Add(ToProtobuf(v)); } } return arrayValue; } private static KeyValueList ToProtobuf(OtlpKeyValueListJson json) { var kvList = new KeyValueList(); if (json.Values is not null) { foreach (var kv in json.Values) { kvList.Values.Add(ToProtobuf(kv)); } } return kvList; } /// <summary> /// Converts a hexadecimal string to a ByteString. /// </summary> /// <param name="hex">The hexadecimal string to convert.</param> /// <returns>A ByteString containing the decoded bytes.</returns> /// <exception cref="ArgumentException">Thrown when the hex string has an odd length.</exception> internal static ByteString HexToByteString(string hex) { if (string.IsNullOrEmpty(hex)) { return ByteString.Empty; } if (hex.Length % 2 != 0) { throw new ArgumentException("Hex string must have an even length.", nameof(hex)); } var hexSpan = hex.AsSpan(); var bytes = new byte[hex.Length / 2]; for (var i = 0; i < bytes.Length; i++) { bytes[i] = byte.Parse(hexSpan.Slice(i * 2, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture); } return ByteString.CopyFrom(bytes); } } /// <summary> /// Converts protobuf types to OTLP JSON types. /// </summary> internal static class OtlpProtobufToJsonConverter { /// <summary> /// Converts an export trace service response from protobuf to JSON. /// </summary> public static OtlpExportTraceServiceResponseJson ToJson(ExportTraceServiceResponse response) { var json = new OtlpExportTraceServiceResponseJson(); if (response.PartialSuccess is not null && (response.PartialSuccess.RejectedSpans > 0 || !string.IsNullOrEmpty(response.PartialSuccess.ErrorMessage))) { json.PartialSuccess = new OtlpExportTracePartialSuccessJson { RejectedSpans = response.PartialSuccess.RejectedSpans, ErrorMessage = response.PartialSuccess.ErrorMessage }; } return json; } /// <summary> /// Converts an export logs service response from protobuf to JSON. /// </summary> public static OtlpExportLogsServiceResponseJson ToJson(ExportLogsServiceResponse response) { var json = new OtlpExportLogsServiceResponseJson(); if (response.PartialSuccess is not null && (response.PartialSuccess.RejectedLogRecords > 0 || !string.IsNullOrEmpty(response.PartialSuccess.ErrorMessage))) { json.PartialSuccess = new OtlpExportLogsPartialSuccessJson { RejectedLogRecords = response.PartialSuccess.RejectedLogRecords, ErrorMessage = response.PartialSuccess.ErrorMessage }; } return json; } /// <summary> /// Converts an export metrics service response from protobuf to JSON. /// </summary> public static OtlpExportMetricsServiceResponseJson ToJson(ExportMetricsServiceResponse response) { var json = new OtlpExportMetricsServiceResponseJson(); if (response.PartialSuccess is not null && (response.PartialSuccess.RejectedDataPoints > 0 || !string.IsNullOrEmpty(response.PartialSuccess.ErrorMessage))) { json.PartialSuccess = new OtlpExportMetricsPartialSuccessJson { RejectedDataPoints = response.PartialSuccess.RejectedDataPoints, ErrorMessage = response.PartialSuccess.ErrorMessage }; } return json; } }