1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package internal
16
17import (
18	otlpcollectorlog "go.opentelemetry.io/collector/model/internal/data/protogen/collector/logs/v1"
19	otlpcollectormetrics "go.opentelemetry.io/collector/model/internal/data/protogen/collector/metrics/v1"
20	otlpcollectortrace "go.opentelemetry.io/collector/model/internal/data/protogen/collector/trace/v1"
21	otlpmetrics "go.opentelemetry.io/collector/model/internal/data/protogen/metrics/v1"
22	otlptrace "go.opentelemetry.io/collector/model/internal/data/protogen/trace/v1"
23)
24
25// MetricsWrapper is an intermediary struct that is declared in an internal package
26// as a way to prevent certain functions of pdata.Metrics data type to be callable by
27// any code outside of this module.
28type MetricsWrapper struct {
29	req *otlpcollectormetrics.ExportMetricsServiceRequest
30}
31
32// MetricsToOtlp internal helper to convert MetricsWrapper to protobuf representation.
33func MetricsToOtlp(mw MetricsWrapper) *otlpcollectormetrics.ExportMetricsServiceRequest {
34	return mw.req
35}
36
37// MetricsFromOtlp internal helper to convert protobuf representation to MetricsWrapper.
38func MetricsFromOtlp(req *otlpcollectormetrics.ExportMetricsServiceRequest) MetricsWrapper {
39	MetricsCompatibilityChanges(req)
40	return MetricsWrapper{req: req}
41}
42
43// MetricsCompatibilityChanges performs backward compatibility conversion on Metrics:
44// - Convert IntHistogram to Histogram. See https://github.com/open-telemetry/opentelemetry-proto/blob/f3b0ee0861d304f8f3126686ba9b01c106069cb0/opentelemetry/proto/metrics/v1/metrics.proto#L170
45// - Convert IntGauge to Gauge. See https://github.com/open-telemetry/opentelemetry-proto/blob/f3b0ee0861d304f8f3126686ba9b01c106069cb0/opentelemetry/proto/metrics/v1/metrics.proto#L156
46// - Convert IntSum to Sum. See https://github.com/open-telemetry/opentelemetry-proto/blob/f3b0ee0861d304f8f3126686ba9b01c106069cb0/opentelemetry/proto/metrics/v1/metrics.proto#L156
47func MetricsCompatibilityChanges(req *otlpcollectormetrics.ExportMetricsServiceRequest) {
48	for _, rsm := range req.ResourceMetrics {
49		for _, ilm := range rsm.InstrumentationLibraryMetrics {
50			for _, metric := range ilm.Metrics {
51				switch m := metric.Data.(type) {
52				case *otlpmetrics.Metric_IntHistogram:
53					metric.Data = intHistogramToHistogram(m)
54				case *otlpmetrics.Metric_IntGauge:
55					metric.Data = intGaugeToGauge(m)
56				case *otlpmetrics.Metric_IntSum:
57					metric.Data = intSumToSum(m)
58				default:
59				}
60			}
61		}
62	}
63}
64
65// TracesWrapper is an intermediary struct that is declared in an internal package
66// as a way to prevent certain functions of pdata.Traces data type to be callable by
67// any code outside of this module.
68type TracesWrapper struct {
69	req *otlpcollectortrace.ExportTraceServiceRequest
70}
71
72// TracesToOtlp internal helper to convert TracesWrapper to protobuf representation.
73func TracesToOtlp(mw TracesWrapper) *otlpcollectortrace.ExportTraceServiceRequest {
74	return mw.req
75}
76
77// TracesFromOtlp internal helper to convert protobuf representation to TracesWrapper.
78func TracesFromOtlp(req *otlpcollectortrace.ExportTraceServiceRequest) TracesWrapper {
79	TracesCompatibilityChanges(req)
80	return TracesWrapper{req: req}
81}
82
83// TracesCompatibilityChanges performs backward compatibility conversion of Span Status code according to
84// OTLP specification as we are a new receiver and sender (we are pushing data to the pipelines):
85// See https://github.com/open-telemetry/opentelemetry-proto/blob/59c488bfb8fb6d0458ad6425758b70259ff4a2bd/opentelemetry/proto/trace/v1/trace.proto#L239
86// See https://github.com/open-telemetry/opentelemetry-proto/blob/59c488bfb8fb6d0458ad6425758b70259ff4a2bd/opentelemetry/proto/trace/v1/trace.proto#L253
87func TracesCompatibilityChanges(req *otlpcollectortrace.ExportTraceServiceRequest) {
88	for _, rss := range req.ResourceSpans {
89		for _, ils := range rss.InstrumentationLibrarySpans {
90			for _, span := range ils.Spans {
91				switch span.Status.Code {
92				case otlptrace.Status_STATUS_CODE_UNSET:
93					if span.Status.DeprecatedCode != otlptrace.Status_DEPRECATED_STATUS_CODE_OK {
94						span.Status.Code = otlptrace.Status_STATUS_CODE_ERROR
95					}
96				case otlptrace.Status_STATUS_CODE_OK:
97					// If status code is set then overwrites deprecated.
98					span.Status.DeprecatedCode = otlptrace.Status_DEPRECATED_STATUS_CODE_OK
99				case otlptrace.Status_STATUS_CODE_ERROR:
100					span.Status.DeprecatedCode = otlptrace.Status_DEPRECATED_STATUS_CODE_UNKNOWN_ERROR
101				}
102			}
103		}
104	}
105}
106
107// LogsWrapper is an intermediary struct that is declared in an internal package
108// as a way to prevent certain functions of pdata.Logs data type to be callable by
109// any code outside of this module.
110type LogsWrapper struct {
111	req *otlpcollectorlog.ExportLogsServiceRequest
112}
113
114// LogsToOtlp internal helper to convert LogsWrapper to protobuf representation.
115func LogsToOtlp(l LogsWrapper) *otlpcollectorlog.ExportLogsServiceRequest {
116	return l.req
117}
118
119// LogsFromOtlp internal helper to convert protobuf representation to LogsWrapper.
120func LogsFromOtlp(req *otlpcollectorlog.ExportLogsServiceRequest) LogsWrapper {
121	return LogsWrapper{req: req}
122}
123
124func intHistogramToHistogram(src *otlpmetrics.Metric_IntHistogram) *otlpmetrics.Metric_Histogram {
125	datapoints := []*otlpmetrics.HistogramDataPoint{}
126	for _, datapoint := range src.IntHistogram.DataPoints {
127		datapoints = append(datapoints, &otlpmetrics.HistogramDataPoint{
128			Labels:            datapoint.Labels,
129			TimeUnixNano:      datapoint.TimeUnixNano,
130			Count:             datapoint.Count,
131			StartTimeUnixNano: datapoint.StartTimeUnixNano,
132			Sum:               float64(datapoint.Sum),
133			BucketCounts:      datapoint.BucketCounts,
134			ExplicitBounds:    datapoint.ExplicitBounds,
135			Exemplars:         intExemplarToExemplar(datapoint.Exemplars),
136		})
137	}
138	return &otlpmetrics.Metric_Histogram{
139		Histogram: &otlpmetrics.Histogram{
140			AggregationTemporality: src.IntHistogram.GetAggregationTemporality(),
141			DataPoints:             datapoints,
142		},
143	}
144}
145
146func intGaugeToGauge(src *otlpmetrics.Metric_IntGauge) *otlpmetrics.Metric_Gauge {
147	datapoints := make([]*otlpmetrics.NumberDataPoint, len(src.IntGauge.DataPoints))
148	for i, datapoint := range src.IntGauge.DataPoints {
149		datapoints[i] = &otlpmetrics.NumberDataPoint{
150			Labels:            datapoint.Labels,
151			TimeUnixNano:      datapoint.TimeUnixNano,
152			StartTimeUnixNano: datapoint.StartTimeUnixNano,
153			Exemplars:         intExemplarToExemplar(datapoint.Exemplars),
154			Value:             &otlpmetrics.NumberDataPoint_AsInt{AsInt: datapoint.Value},
155		}
156	}
157	return &otlpmetrics.Metric_Gauge{
158		Gauge: &otlpmetrics.Gauge{
159			DataPoints: datapoints,
160		},
161	}
162}
163
164func intSumToSum(src *otlpmetrics.Metric_IntSum) *otlpmetrics.Metric_Sum {
165	datapoints := make([]*otlpmetrics.NumberDataPoint, len(src.IntSum.DataPoints))
166	for i, datapoint := range src.IntSum.DataPoints {
167		datapoints[i] = &otlpmetrics.NumberDataPoint{
168			Labels:            datapoint.Labels,
169			TimeUnixNano:      datapoint.TimeUnixNano,
170			StartTimeUnixNano: datapoint.StartTimeUnixNano,
171			Exemplars:         intExemplarToExemplar(datapoint.Exemplars),
172			Value:             &otlpmetrics.NumberDataPoint_AsInt{AsInt: datapoint.Value},
173		}
174	}
175	return &otlpmetrics.Metric_Sum{
176		Sum: &otlpmetrics.Sum{
177			AggregationTemporality: src.IntSum.AggregationTemporality,
178			DataPoints:             datapoints,
179			IsMonotonic:            src.IntSum.IsMonotonic,
180		},
181	}
182}
183
184func intExemplarToExemplar(src []otlpmetrics.IntExemplar) []otlpmetrics.Exemplar { //nolint:staticcheck // SA1019 ignore this!
185	exemplars := []otlpmetrics.Exemplar{}
186	for _, exemplar := range src {
187		exemplars = append(exemplars, otlpmetrics.Exemplar{
188			FilteredLabels: exemplar.FilteredLabels,
189			TimeUnixNano:   exemplar.TimeUnixNano,
190			Value: &otlpmetrics.Exemplar_AsInt{
191				AsInt: exemplar.Value,
192			},
193			SpanId:  exemplar.SpanId,
194			TraceId: exemplar.TraceId,
195		})
196	}
197	return exemplars
198}
199