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 otlptest 16 17import ( 18 "sort" 19 20 collectormetricpb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/collector/metrics/v1" 21 collectortracepb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/collector/trace/v1" 22 commonpb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/common/v1" 23 metricpb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/metrics/v1" 24 resourcepb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/resource/v1" 25 tracepb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/trace/v1" 26) 27 28// Collector is an interface that mock collectors should implements, 29// so they can be used for the end-to-end testing. 30type Collector interface { 31 Stop() error 32 GetResourceSpans() []*tracepb.ResourceSpans 33 GetMetrics() []*metricpb.Metric 34} 35 36// SpansStorage stores the spans. Mock collectors could use it to 37// store spans they have received. 38type SpansStorage struct { 39 rsm map[string]*tracepb.ResourceSpans 40 spanCount int 41} 42 43// MetricsStorage stores the metrics. Mock collectors could use it to 44// store metrics they have received. 45type MetricsStorage struct { 46 metrics []*metricpb.Metric 47} 48 49// NewSpansStorage creates a new spans storage. 50func NewSpansStorage() SpansStorage { 51 return SpansStorage{ 52 rsm: make(map[string]*tracepb.ResourceSpans), 53 } 54} 55 56// AddSpans adds spans to the spans storage. 57func (s *SpansStorage) AddSpans(request *collectortracepb.ExportTraceServiceRequest) { 58 for _, rs := range request.GetResourceSpans() { 59 rstr := resourceString(rs.Resource) 60 if existingRs, ok := s.rsm[rstr]; !ok { 61 s.rsm[rstr] = rs 62 // TODO (rghetia): Add support for library Info. 63 if len(rs.InstrumentationLibrarySpans) == 0 { 64 rs.InstrumentationLibrarySpans = []*tracepb.InstrumentationLibrarySpans{ 65 { 66 Spans: []*tracepb.Span{}, 67 }, 68 } 69 } 70 s.spanCount += len(rs.InstrumentationLibrarySpans[0].Spans) 71 } else { 72 if len(rs.InstrumentationLibrarySpans) > 0 { 73 newSpans := rs.InstrumentationLibrarySpans[0].GetSpans() 74 existingRs.InstrumentationLibrarySpans[0].Spans = 75 append(existingRs.InstrumentationLibrarySpans[0].Spans, 76 newSpans...) 77 s.spanCount += len(newSpans) 78 } 79 } 80 } 81} 82 83// GetSpans returns the stored spans. 84func (s *SpansStorage) GetSpans() []*tracepb.Span { 85 spans := make([]*tracepb.Span, 0, s.spanCount) 86 for _, rs := range s.rsm { 87 spans = append(spans, rs.InstrumentationLibrarySpans[0].Spans...) 88 } 89 return spans 90} 91 92// GetResourceSpans returns the stored resource spans. 93func (s *SpansStorage) GetResourceSpans() []*tracepb.ResourceSpans { 94 rss := make([]*tracepb.ResourceSpans, 0, len(s.rsm)) 95 for _, rs := range s.rsm { 96 rss = append(rss, rs) 97 } 98 return rss 99} 100 101// NewMetricsStorage creates a new metrics storage. 102func NewMetricsStorage() MetricsStorage { 103 return MetricsStorage{} 104} 105 106// AddMetrics adds metrics to the metrics storage. 107func (s *MetricsStorage) AddMetrics(request *collectormetricpb.ExportMetricsServiceRequest) { 108 for _, rm := range request.GetResourceMetrics() { 109 // TODO (rghetia) handle multiple resource and library info. 110 if len(rm.InstrumentationLibraryMetrics) > 0 { 111 s.metrics = append(s.metrics, rm.InstrumentationLibraryMetrics[0].Metrics...) 112 } 113 } 114} 115 116// GetMetrics returns the stored metrics. 117func (s *MetricsStorage) GetMetrics() []*metricpb.Metric { 118 // copy in order to not change. 119 m := make([]*metricpb.Metric, 0, len(s.metrics)) 120 return append(m, s.metrics...) 121} 122 123func resourceString(res *resourcepb.Resource) string { 124 sAttrs := sortedAttributes(res.GetAttributes()) 125 rstr := "" 126 for _, attr := range sAttrs { 127 rstr = rstr + attr.String() 128 } 129 return rstr 130} 131 132func sortedAttributes(attrs []*commonpb.KeyValue) []*commonpb.KeyValue { 133 sort.Slice(attrs[:], func(i, j int) bool { 134 return attrs[i].Key < attrs[j].Key 135 }) 136 return attrs 137} 138