diff --git a/internal/goldendataset/generator_commons.go b/internal/goldendataset/generator_commons.go new file mode 100644 index 00000000000..6a276cb17c9 --- /dev/null +++ b/internal/goldendataset/generator_commons.go @@ -0,0 +1,105 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +import ( + "encoding/csv" + "io" + "os" + "path/filepath" + + otlpcommon "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1" + "github.com/spf13/cast" +) + +func convertMapToAttributeKeyValues(attrsMap map[string]interface{}) []*otlpcommon.AttributeKeyValue { + if attrsMap == nil { + return nil + } + attrList := make([]*otlpcommon.AttributeKeyValue, len(attrsMap)) + index := 0 + for key, value := range attrsMap { + attrList[index] = constructAttributeKeyValue(key, value) + index++ + } + return attrList +} + +func constructAttributeKeyValue(key string, value interface{}) *otlpcommon.AttributeKeyValue { + var attr otlpcommon.AttributeKeyValue + switch val := value.(type) { + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + attr = otlpcommon.AttributeKeyValue{ + Key: key, + Type: otlpcommon.AttributeKeyValue_INT, + IntValue: cast.ToInt64(val), + } + case float32, float64: + attr = otlpcommon.AttributeKeyValue{ + Key: key, + Type: otlpcommon.AttributeKeyValue_DOUBLE, + DoubleValue: cast.ToFloat64(val), + } + case bool: + attr = otlpcommon.AttributeKeyValue{ + Key: key, + Type: otlpcommon.AttributeKeyValue_BOOL, + BoolValue: cast.ToBool(val), + } + default: + attr = otlpcommon.AttributeKeyValue{ + Key: key, + Type: otlpcommon.AttributeKeyValue_STRING, + StringValue: val.(string), + } + } + return &attr +} + +func loadPictOutputFile(fileName string) ([][]string, error) { + file, err := os.Open(filepath.Clean(fileName)) + if err != nil { + return nil, err + } + defer func() { + cerr := file.Close() + if err == nil { + err = cerr + } + }() + + reader := csv.NewReader(file) + reader.Comma = '\t' + + return reader.ReadAll() +} + +func generateTraceID(random io.Reader) []byte { + var r [16]byte + _, err := random.Read(r[:]) + if err != nil { + panic(err) + } + return r[:] +} + +func generateSpanID(random io.Reader) []byte { + var r [8]byte + _, err := random.Read(r[:]) + if err != nil { + panic(err) + } + return r[:] +} diff --git a/internal/goldendataset/pict_tracing_input_defs.go b/internal/goldendataset/pict_tracing_input_defs.go new file mode 100644 index 00000000000..c818cf0b0b3 --- /dev/null +++ b/internal/goldendataset/pict_tracing_input_defs.go @@ -0,0 +1,184 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +//// Start of PICT inputs for generating golden dataset ResourceSpans (pict_input_traces.txt) //// + +// Input columns in pict_input_traces.txt +const ( + TracesColumnResource = 0 + TracesColumnInstrumentationLibrary = 1 + TracesColumnSpans = 2 +) + +// Enumerates the supported types of resource instances that can be generated. +type PICTInputResource string + +const ( + ResourceNil PICTInputResource = "Nil" + ResourceEmpty PICTInputResource = "Empty" + ResourceVMOnPrem PICTInputResource = "VMOnPrem" + ResourceVMCloud PICTInputResource = "VMCloud" + ResourceK8sOnPrem PICTInputResource = "K8sOnPrem" + ResourceK8sCloud PICTInputResource = "K8sCloud" + ResourceFaas PICTInputResource = "Faas" +) + +// Enumerates the number and kind of instrumentation library instances that can be generated. +type PICTInputInstrumentationLibrary string + +const ( + LibraryNone PICTInputInstrumentationLibrary = "None" + LibraryOne PICTInputInstrumentationLibrary = "One" + LibraryTwo PICTInputInstrumentationLibrary = "Two" +) + +// Enumerates the relative sizes of tracing spans that can be attached to an instrumentation library span instance. +type PICTInputSpans string + +const ( + LibrarySpansNone PICTInputSpans = "None" + LibrarySpansOne PICTInputSpans = "One" + LibrarySpansSeveral PICTInputSpans = "Several" + LibrarySpansAll PICTInputSpans = "All" +) + +// PICTTracingInputs defines one pairwise combination of ResourceSpans variations +type PICTTracingInputs struct { + // Specifies the category of attributes to populate the Resource field with + Resource PICTInputResource + // Specifies the number and library categories to populte the InstrumentationLibrarySpans field with + InstrumentationLibrary PICTInputInstrumentationLibrary + // Specifies the relative number of spans to populate the InstrumentationLibrarySpans' Spans field with + Spans PICTInputSpans +} + +//// Start of PICT inputs for generating golden dataset Spans (pict_input_spans.txt) //// + +// Input columns in pict_input_spans.txt +const ( + SpansColumnParent = 0 + SpansColumnTracestate = 1 + SpansColumnKind = 2 + SpansColumnAttributes = 3 + SpansColumnEvents = 4 + SpansColumnLinks = 5 + SpansColumnStatus = 6 +) + +// Enumerates the parent/child types of spans that can be generated. +type PICTInputParent string + +const ( + SpanParentRoot PICTInputParent = "Root" + SpanParentChild PICTInputParent = "Child" +) + +// Enumerates the categories of tracestate values that can be generated for a span. +type PICTInputTracestate string + +const ( + TraceStateEmpty PICTInputTracestate = "Empty" + TraceStateOne PICTInputTracestate = "One" + TraceStateFour PICTInputTracestate = "Four" +) + +// Enumerates the span kind values that can be set for a span. +type PICTInputKind string + +const ( + SpanKindUnspecified PICTInputKind = "Unspecified" + SpanKindInternal PICTInputKind = "Internal" + SpanKindServer PICTInputKind = "Server" + SpanKindClient PICTInputKind = "Client" + SpanKindProducer PICTInputKind = "Producer" + SpanKindConsumer PICTInputKind = "Consumer" +) + +// Enumerates the categories of representative attributes a generated span can be populated with. +type PICTInputAttributes string + +const ( + SpanAttrNil PICTInputAttributes = "Nil" + SpanAttrEmpty PICTInputAttributes = "Empty" + SpanAttrDatabaseSQL PICTInputAttributes = "DatabaseSQL" + SpanAttrDatabaseNoSQL PICTInputAttributes = "DatabaseNoSQL" + SpanAttrFaaSDatasource PICTInputAttributes = "FaaSDatasource" + SpanAttrFaaSHTTP PICTInputAttributes = "FaaSHTTP" + SpanAttrFaaSPubSub PICTInputAttributes = "FaaSPubSub" + SpanAttrFaaSTimer PICTInputAttributes = "FaaSTimer" + SpanAttrFaaSOther PICTInputAttributes = "FaaSOther" + SpanAttrHTTPClient PICTInputAttributes = "HTTPClient" + SpanAttrHTTPServer PICTInputAttributes = "HTTPServer" + SpanAttrMessagingProducer PICTInputAttributes = "MessagingProducer" + SpanAttrMessagingConsumer PICTInputAttributes = "MessagingConsumer" + SpanAttrGRPCClient PICTInputAttributes = "gRPCClient" + SpanAttrGRPCServer PICTInputAttributes = "gRPCServer" + SpanAttrInternal PICTInputAttributes = "Internal" + SpanAttrMaxCount PICTInputAttributes = "MaxCount" +) + +// Enumerates the categories of events and/or links a generated span can be populated with. +type PICTInputSpanChild string + +const ( + SpanChildCountNil PICTInputSpanChild = "Nil" + SpanChildCountEmpty PICTInputSpanChild = "Empty" + SpanChildCountOne PICTInputSpanChild = "One" + SpanChildCountTwo PICTInputSpanChild = "Two" + SpanChildCountEight PICTInputSpanChild = "Eight" +) + +// Enumerates the status values a generated span can be populated with. +type PICTInputStatus string + +const ( + SpanStatusNil PICTInputStatus = "Nil" + SpanStatusOk PICTInputStatus = "Ok" + SpanStatusCancelled PICTInputStatus = "Cancelled" + SpanStatusUnknownError PICTInputStatus = "UnknownError" + SpanStatusInvalidArgument PICTInputStatus = "InvalidArgument" + SpanStatusDeadlineExceeded PICTInputStatus = "DeadlineExceeded" + SpanStatusNotFound PICTInputStatus = "NotFound" + SpanStatusAlreadyExists PICTInputStatus = "AlreadyExists" + SpanStatusPermissionDenied PICTInputStatus = "PermissionDenied" + SpanStatusResourceExhausted PICTInputStatus = "ResourceExhausted" + SpanStatusFailedPrecondition PICTInputStatus = "FailedPrecondition" + SpanStatusAborted PICTInputStatus = "Aborted" + SpanStatusOutOfRange PICTInputStatus = "OutOfRange" + SpanStatusUnimplemented PICTInputStatus = "Unimplemented" + SpanStatusInternalError PICTInputStatus = "InternalError" + SpanStatusUnavailable PICTInputStatus = "Unavailable" + SpanStatusDataLoss PICTInputStatus = "DataLoss" + SpanStatusUnauthenticated PICTInputStatus = "Unauthenticated" +) + +// PICTSpanInputs defines one pairwise combination of Span variations +type PICTSpanInputs struct { + // Specifies whether the ParentSpanId field should be populated or not + Parent PICTInputParent + // Specifies the category of contents to populate the TraceState field with + Tracestate PICTInputTracestate + // Specifies the value to populate the Kind field with + Kind PICTInputKind + // Specifies the category of values to populate the Attributes field with + Attributes PICTInputAttributes + // Specifies the category of contents to populate the Events field with + Events PICTInputSpanChild + // Specifies the category of contents to populate the Links field with + Links PICTInputSpanChild + // Specifies the value to populate the Status field with + Status PICTInputStatus +} diff --git a/internal/goldendataset/resource_generator.go b/internal/goldendataset/resource_generator.go new file mode 100644 index 00000000000..ef350190fbb --- /dev/null +++ b/internal/goldendataset/resource_generator.go @@ -0,0 +1,144 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +import ( + otlpresource "github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1" + + "go.opentelemetry.io/collector/translator/conventions" +) + +//GenerateResource generates a OTLP Resource object with representative attributes for the +//underlying resource type specified by the rscID input parameter. +func GenerateResource(rscID PICTInputResource) *otlpresource.Resource { + var attrs map[string]interface{} + switch rscID { + case ResourceNil: + attrs = generateNilAttributes() + case ResourceEmpty: + attrs = generateEmptyAttributes() + case ResourceVMOnPrem: + attrs = generateOnpremVMAttributes() + case ResourceVMCloud: + attrs = generateCloudVMAttributes() + case ResourceK8sOnPrem: + attrs = generateOnpremK8sAttributes() + case ResourceK8sCloud: + attrs = generateCloudK8sAttributes() + case ResourceFaas: + attrs = generateFassAttributes() + default: + attrs = generateEmptyAttributes() + } + var dropped uint32 + if len(attrs) < 10 { + dropped = 0 + } else { + dropped = uint32(len(attrs) % 4) + } + return &otlpresource.Resource{ + Attributes: convertMapToAttributeKeyValues(attrs), + DroppedAttributesCount: dropped, + } +} + +func generateNilAttributes() map[string]interface{} { + return nil +} + +func generateEmptyAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + return attrMap +} + +func generateOnpremVMAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeServiceName] = "customers" + attrMap[conventions.AttributeServiceNamespace] = "production" + attrMap[conventions.AttributeServiceVersion] = "semver:0.7.3" + attrMap[conventions.AttributeHostHostname] = "tc-prod9.internal.example.com" + attrMap[conventions.AttributeHostName] = "172.18.36.18" + attrMap[conventions.AttributeHostImageID] = "661ADFA6-E293-4870-9EFA-1AA052C49F18" + attrMap[conventions.AttributeTelemetrySDKLanguage] = "java" + attrMap[conventions.AttributeTelemetrySDKName] = "opentelemetry" + attrMap[conventions.AttributeTelemetrySDKVersion] = "0.3.0" + return attrMap +} + +func generateCloudVMAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeServiceName] = "shoppingcart" + attrMap[conventions.AttributeServiceName] = "customers" + attrMap[conventions.AttributeServiceNamespace] = "production" + attrMap[conventions.AttributeServiceVersion] = "semver:0.7.3" + attrMap[conventions.AttributeTelemetrySDKLanguage] = "java" + attrMap[conventions.AttributeTelemetrySDKName] = "opentelemetry" + attrMap[conventions.AttributeTelemetrySDKVersion] = "0.3.0" + attrMap[conventions.AttributeHostHostname] = "env-check" + attrMap[conventions.AttributeHostID] = "57e8add1f79a454bae9fb1f7756a009a" + attrMap[conventions.AttributeHostName] = "10.0.0.4" + attrMap[conventions.AttributeHostImageID] = "5.3.0-1020-azure" + attrMap[conventions.AttributeHostType] = "B1ms" + attrMap[conventions.AttributeCloudProvider] = "azure" + attrMap[conventions.AttributeCloudAccount] = "2f5b8278-4b80-4930-a6bb-d86fc63a2534" + attrMap[conventions.AttributeCloudRegion] = "South Central US" + return attrMap +} + +func generateOnpremK8sAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeContainerName] = "cert-manager" + attrMap[conventions.AttributeContainerImage] = "quay.io/jetstack/cert-manager-controller:v0.14.2" + attrMap[conventions.AttributeK8sCluster] = "docker-desktop" + attrMap[conventions.AttributeK8sNamespace] = "cert-manager" + attrMap[conventions.AttributeK8sDeployment] = "cm-1-cert-manager" + attrMap[conventions.AttributeK8sPod] = "cm-1-cert-manager-6448b4949b-t2jtd" + attrMap[conventions.AttributeHostHostname] = "docker-desktop" + attrMap[conventions.AttributeHostName] = "192.168.65.3" + return attrMap +} + +func generateCloudK8sAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeContainerName] = "otel-collector" + attrMap[conventions.AttributeContainerImage] = "otel/opentelemetry-collector-contrib" + attrMap[conventions.AttributeContainerTag] = "0.4.0" + attrMap[conventions.AttributeK8sCluster] = "erp-dev" + attrMap[conventions.AttributeK8sNamespace] = "monitoring" + attrMap[conventions.AttributeK8sDeployment] = "otel-collector" + attrMap[conventions.AttributeK8sPod] = "otel-collector-6484db5844-c6f9m" + attrMap[conventions.AttributeHostHostname] = "ip-10-99-118-157.ec2.internal" + attrMap[conventions.AttributeHostID] = "ec2e3fdaffa294348bdf355156b94cda" + attrMap[conventions.AttributeHostName] = "10.99.118.157" + attrMap[conventions.AttributeHostImageID] = "ami-011c865bf7da41a9d" + attrMap[conventions.AttributeHostType] = "m5.xlarge" + attrMap[conventions.AttributeCloudProvider] = "aws" + attrMap[conventions.AttributeCloudAccount] = "12345678901" + attrMap[conventions.AttributeCloudRegion] = "us-east-1" + attrMap[conventions.AttributeCloudZone] = "us-east-1c" + return attrMap +} + +func generateFassAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeFaasID] = "https://us-central1-dist-system-demo.cloudfunctions.net/env-vars-print" + attrMap[conventions.AttributeFaasName] = "env-vars-print" + attrMap[conventions.AttributeFaasVersion] = "semver:1.0.0" + attrMap[conventions.AttributeCloudProvider] = "gcp" + attrMap[conventions.AttributeCloudAccount] = "opentelemetry" + attrMap[conventions.AttributeCloudRegion] = "us-central1" + attrMap[conventions.AttributeCloudZone] = "us-central1-a" + return attrMap +} diff --git a/internal/goldendataset/resource_generator_test.go b/internal/goldendataset/resource_generator_test.go new file mode 100644 index 00000000000..a7a6ad20b31 --- /dev/null +++ b/internal/goldendataset/resource_generator_test.go @@ -0,0 +1,49 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +import ( + "testing" + + "github.com/golang/protobuf/proto" + otlpresource "github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1" + "github.com/stretchr/testify/assert" +) + +func TestGenerateResource(t *testing.T) { + resourceIds := []PICTInputResource{ResourceNil, ResourceEmpty, ResourceVMOnPrem, ResourceVMCloud, ResourceK8sOnPrem, + ResourceK8sCloud, ResourceFaas} + for _, rscID := range resourceIds { + rsc := GenerateResource(rscID) + if rscID == ResourceNil { + assert.Nil(t, rsc.Attributes) + } else { + assert.NotNil(t, rsc.Attributes) + } + // test marshal/unmarshal + bytes, err := proto.Marshal(rsc) + if err != nil { + assert.Fail(t, err.Error()) + } + if len(bytes) > 0 { + copy := &otlpresource.Resource{} + err = proto.Unmarshal(bytes, copy) + if err != nil { + assert.Fail(t, err.Error()) + } + assert.EqualValues(t, len(rsc.Attributes), len(copy.Attributes)) + } + } +} diff --git a/internal/goldendataset/span_generator.go b/internal/goldendataset/span_generator.go new file mode 100644 index 00000000000..134b9e6ee29 --- /dev/null +++ b/internal/goldendataset/span_generator.go @@ -0,0 +1,514 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +import ( + "fmt" + "io" + "time" + + otlpcommon "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1" + otlptrace "github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1" + + "go.opentelemetry.io/collector/translator/conventions" +) + +var statusCodeMap = map[PICTInputStatus]otlptrace.Status_StatusCode{ + SpanStatusOk: otlptrace.Status_Ok, + SpanStatusCancelled: otlptrace.Status_Cancelled, + SpanStatusUnknownError: otlptrace.Status_UnknownError, + SpanStatusInvalidArgument: otlptrace.Status_InvalidArgument, + SpanStatusDeadlineExceeded: otlptrace.Status_DeadlineExceeded, + SpanStatusNotFound: otlptrace.Status_NotFound, + SpanStatusAlreadyExists: otlptrace.Status_AlreadyExists, + SpanStatusPermissionDenied: otlptrace.Status_PermissionDenied, + SpanStatusResourceExhausted: otlptrace.Status_ResourceExhausted, + SpanStatusFailedPrecondition: otlptrace.Status_FailedPrecondition, + SpanStatusAborted: otlptrace.Status_Aborted, + SpanStatusOutOfRange: otlptrace.Status_OutOfRange, + SpanStatusUnimplemented: otlptrace.Status_Unimplemented, + SpanStatusInternalError: otlptrace.Status_InternalError, + SpanStatusUnavailable: otlptrace.Status_Unavailable, + SpanStatusDataLoss: otlptrace.Status_DataLoss, + SpanStatusUnauthenticated: otlptrace.Status_Unauthenticated, +} + +var statusMsgMap = map[PICTInputStatus]string{ + SpanStatusOk: "", + SpanStatusCancelled: "Cancellation received", + SpanStatusUnknownError: "", + SpanStatusInvalidArgument: "parameter is required", + SpanStatusDeadlineExceeded: "timed out after 30002 ms", + SpanStatusNotFound: "/dragons/RomanianLonghorn not found", + SpanStatusAlreadyExists: "/dragons/Drogon already exists", + SpanStatusPermissionDenied: "tlannister does not have write permission", + SpanStatusResourceExhausted: "ResourceExhausted", + SpanStatusFailedPrecondition: "33a64df551425fcc55e4d42a148795d9f25f89d4 has been edited", + SpanStatusAborted: "", + SpanStatusOutOfRange: "Range Not Satisfiable", + SpanStatusUnimplemented: "Unimplemented", + SpanStatusInternalError: "java.lang.NullPointerException", + SpanStatusUnavailable: "RecommendationService is currently unavailable", + SpanStatusDataLoss: "", + SpanStatusUnauthenticated: "nstark is unknown user", +} + +//GenerateSpans generates a slice of OTLP Span objects with the number of spans specified by the count input +//parameter. The startPos parameter specifies the line in the PICT tool-generated, test parameter +//combination records file specified by the pictFile parameter to start reading from. When the end record +//is reached it loops back to the first record. The random parameter injects the random number generator +//to use in generating IDs and other random values. Using a random number generator with the same seed value +//enables reproducible tests. +// +//The return values are the slice with the generated spans, the starting position for the next generation +//run and the error which caused the spans generation to fail. If err is not nil, the spans slice will +//have nil values. +func GenerateSpans(count int, startPos int, pictFile string, random io.Reader) ([]*otlptrace.Span, int, error) { + pairsData, err := loadPictOutputFile(pictFile) + if err != nil { + return nil, 0, err + } + pairsTotal := len(pairsData) + spanList := make([]*otlptrace.Span, count) + index := startPos + 1 + var inputs []string + var spanInputs *PICTSpanInputs + var traceID []byte + var parentID []byte + for i := 0; i < count; i++ { + if index >= pairsTotal { + index = 1 + } + inputs = pairsData[index] + spanInputs = &PICTSpanInputs{ + Parent: PICTInputParent(inputs[SpansColumnParent]), + Tracestate: PICTInputTracestate(inputs[SpansColumnTracestate]), + Kind: PICTInputKind(inputs[SpansColumnKind]), + Attributes: PICTInputAttributes(inputs[SpansColumnAttributes]), + Events: PICTInputSpanChild(inputs[SpansColumnEvents]), + Links: PICTInputSpanChild(inputs[SpansColumnLinks]), + Status: PICTInputStatus(inputs[SpansColumnStatus]), + } + switch spanInputs.Parent { + case SpanParentRoot: + traceID = generateTraceID(random) + parentID = nil + case SpanParentChild: + // use existing if available + if traceID == nil { + traceID = generateTraceID(random) + } + if parentID == nil { + parentID = generateSpanID(random) + } + } + spanName := generateSpanName(spanInputs) + spanList[i] = GenerateSpan(traceID, parentID, spanName, spanInputs, random) + parentID = spanList[i].SpanId + index++ + } + return spanList, index, nil +} + +func generateSpanName(spanInputs *PICTSpanInputs) string { + return fmt.Sprintf("/%s/%s/%s/%s/%s/%s/%s", spanInputs.Parent, spanInputs.Tracestate, spanInputs.Kind, + spanInputs.Attributes, spanInputs.Events, spanInputs.Links, spanInputs.Status) +} + +//GenerateSpan generates a single OTLP Span based on the input values provided. They are: +// traceID - the trace ID to use, should not be nil +// parentID - the parent span ID or nil if it is a root span +// spanName - the span name, should not be blank +// spanInputs - the pairwise combination of field value variations for this span +// random - the random number generator to use in generating ID values +// +//The generated span is returned. +func GenerateSpan(traceID []byte, parentID []byte, spanName string, spanInputs *PICTSpanInputs, + random io.Reader) *otlptrace.Span { + endTime := time.Now().Add(-50 * time.Microsecond) + return &otlptrace.Span{ + TraceId: traceID, + SpanId: generateSpanID(random), + TraceState: generateTraceState(spanInputs.Tracestate), + ParentSpanId: parentID, + Name: spanName, + Kind: lookupSpanKind(spanInputs.Kind), + StartTimeUnixNano: uint64(endTime.Add(-215 * time.Millisecond).UnixNano()), + EndTimeUnixNano: uint64(endTime.UnixNano()), + Attributes: generateSpanAttributes(spanInputs.Attributes), + DroppedAttributesCount: 0, + Events: generateSpanEvents(spanInputs.Events), + DroppedEventsCount: 0, + Links: generateSpanLinks(spanInputs.Links, random), + DroppedLinksCount: 0, + Status: generateStatus(spanInputs.Status), + } +} + +func generateTraceState(tracestate PICTInputTracestate) string { + switch tracestate { + case TraceStateOne: + return "lasterror=f39cd56cc44274fd5abd07ef1164246d10ce2955" + case TraceStateFour: + return "err@ck=80ee5638,rate@ck=1.62,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE" + case TraceStateEmpty: + fallthrough + default: + return "" + } +} + +func lookupSpanKind(kind PICTInputKind) otlptrace.Span_SpanKind { + switch kind { + case SpanKindClient: + return otlptrace.Span_CLIENT + case SpanKindServer: + return otlptrace.Span_SERVER + case SpanKindProducer: + return otlptrace.Span_PRODUCER + case SpanKindConsumer: + return otlptrace.Span_CONSUMER + case SpanKindInternal: + return otlptrace.Span_INTERNAL + case SpanKindUnspecified: + fallthrough + default: + return otlptrace.Span_SPAN_KIND_UNSPECIFIED + } +} + +func generateSpanAttributes(spanTypeID PICTInputAttributes) []*otlpcommon.AttributeKeyValue { + var attrs map[string]interface{} + switch spanTypeID { + case SpanAttrNil: + attrs = nil + case SpanAttrEmpty: + attrs = make(map[string]interface{}) + case SpanAttrDatabaseSQL: + attrs = generateDatabaseSQLAttributes() + case SpanAttrDatabaseNoSQL: + attrs = generateDatabaseNoSQLAttributes() + case SpanAttrFaaSDatasource: + attrs = generateFaaSDatasourceAttributes() + case SpanAttrFaaSHTTP: + attrs = generateFaaSHTTPAttributes() + case SpanAttrFaaSPubSub: + attrs = generateFaaSPubSubAttributes() + case SpanAttrFaaSTimer: + attrs = generateFaaSTimerAttributes() + case SpanAttrFaaSOther: + attrs = generateFaaSOtherAttributes() + case SpanAttrHTTPClient: + attrs = generateHTTPClientAttributes() + case SpanAttrHTTPServer: + attrs = generateHTTPServerAttributes() + case SpanAttrMessagingProducer: + attrs = generateMessagingProducerAttributes() + case SpanAttrMessagingConsumer: + attrs = generateMessagingConsumerAttributes() + case SpanAttrGRPCClient: + attrs = generateGRPCClientAttributes() + case SpanAttrGRPCServer: + attrs = generateGRPCServerAttributes() + case SpanAttrInternal: + attrs = generateInternalAttributes() + case SpanAttrMaxCount: + attrs = generateMaxCountAttributes() + default: + attrs = generateGRPCClientAttributes() + } + return convertMapToAttributeKeyValues(attrs) +} + +func generateStatus(statusStr PICTInputStatus) *otlptrace.Status { + if SpanStatusNil == statusStr { + return nil + } + return &otlptrace.Status{ + Code: statusCodeMap[statusStr], + Message: statusMsgMap[statusStr], + } +} + +func generateDatabaseSQLAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeDBType] = "sql" + attrMap[conventions.AttributeDBInstance] = "inventory" + attrMap[conventions.AttributeDBStatement] = + "SELECT c.product_catg_id, c.catg_name, c.description, c.html_frag, c.image_url, p.name FROM product_catg c OUTER JOIN product p ON c.product_catg_id=p.product_catg_id WHERE c.product_catg_id = :catgId" + attrMap[conventions.AttributeDBUser] = "invsvc" + attrMap[conventions.AttributeDBURL] = "jdbc:postgresql://invdev.cdsr3wfqepqo.us-east-1.rds.amazonaws.com:5432/inventory" + attrMap[conventions.AttributeNetPeerIP] = "172.30.2.7" + attrMap[conventions.AttributeNetPeerPort] = int64(5432) + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateDatabaseNoSQLAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeDBType] = "cosmosdb" + attrMap[conventions.AttributeDBInstance] = "graphdb" + attrMap[conventions.AttributeDBStatement] = "g.V().hasLabel('postive').has('age', gt(65)).values('geocode')" + attrMap[conventions.AttributeDBURL] = "wss://contacttrace.gremlin.cosmos.azure.com:443/" + attrMap[conventions.AttributeNetPeerIP] = "10.118.17.63" + attrMap[conventions.AttributeNetPeerPort] = int64(443) + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateFaaSDatasourceAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeFaaSTrigger] = conventions.FaaSTriggerDataSource + attrMap[conventions.AttributeFaaSExecution] = "DB85AF51-5E13-473D-8454-1E2D59415EAB" + attrMap[conventions.AttributeFaaSDocumentCollection] = "faa-flight-delay-information-incoming" + attrMap[conventions.AttributeFaaSDocumentOperation] = "insert" + attrMap[conventions.AttributeFaaSDocumentTime] = "2020-05-09T19:50:06Z" + attrMap[conventions.AttributeFaaSDocumentName] = "delays-20200509-13.csv" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateFaaSHTTPAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeFaaSTrigger] = conventions.FaaSTriggerHTTP + attrMap[conventions.AttributeHTTPMethod] = "POST" + attrMap[conventions.AttributeHTTPScheme] = "https" + attrMap[conventions.AttributeHTTPHost] = "api.opentelemetry.io" + attrMap[conventions.AttributeHTTPTarget] = "/blog/posts" + attrMap[conventions.AttributeHTTPFlavor] = "2" + attrMap[conventions.AttributeHTTPStatusCode] = int64(201) + attrMap[conventions.AttributeHTTPUserAgent] = + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateFaaSPubSubAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeFaaSTrigger] = conventions.FaaSTriggerPubSub + attrMap[conventions.AttributeMessagingSystem] = "sqs" + attrMap[conventions.AttributeMessagingDestination] = "video-views-au" + attrMap[conventions.AttributeMessagingOperation] = "process" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateFaaSTimerAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeFaaSTrigger] = conventions.FaaSTriggerTimer + attrMap[conventions.AttributeFaaSExecution] = "73103A4C-E22F-4493-BDE8-EAE5CAB37B50" + attrMap[conventions.AttributeFaaSTime] = "2020-05-09T20:00:08Z" + attrMap[conventions.AttributeFaaSCron] = "0/15 * * * *" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateFaaSOtherAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeFaaSTrigger] = conventions.FaaSTriggerOther + attrMap["processed.count"] = int64(256) + attrMap["processed.data"] = 14.46 + attrMap["processed.errors"] = false + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateHTTPClientAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeHTTPMethod] = "GET" + attrMap[conventions.AttributeHTTPURL] = "https://opentelemetry.io/registry/" + attrMap[conventions.AttributeHTTPStatusCode] = int64(200) + attrMap[conventions.AttributeHTTPStatusText] = "More Than OK" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateHTTPServerAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeHTTPMethod] = "POST" + attrMap[conventions.AttributeHTTPScheme] = "https" + attrMap[conventions.AttributeHTTPServerName] = "api22.opentelemetry.io" + attrMap[conventions.AttributeNetHostPort] = int64(443) + attrMap[conventions.AttributeHTTPTarget] = "/blog/posts" + attrMap[conventions.AttributeHTTPFlavor] = "2" + attrMap[conventions.AttributeHTTPStatusCode] = int64(201) + attrMap[conventions.AttributeHTTPUserAgent] = + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36" + attrMap[conventions.AttributeHTTPRoute] = "/blog/posts" + attrMap[conventions.AttributeHTTPClientIP] = "2001:506:71f0:16e::1" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateMessagingProducerAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeMessagingSystem] = "nats" + attrMap[conventions.AttributeMessagingDestination] = "time.us.east.atlanta" + attrMap[conventions.AttributeMessagingDestinationKind] = "topic" + attrMap[conventions.AttributeMessagingMessageID] = "AA7C5438-D93A-43C8-9961-55613204648F" + attrMap["messaging.sequence"] = int64(1) + attrMap[conventions.AttributeNetPeerIP] = "10.10.212.33" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateMessagingConsumerAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeMessagingSystem] = "kafka" + attrMap[conventions.AttributeMessagingDestination] = "infrastructure-events-zone1" + attrMap[conventions.AttributeMessagingOperation] = "receive" + attrMap[conventions.AttributeNetPeerIP] = "2600:1700:1f00:11c0:4de0:c223:a800:4e87" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateGRPCClientAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeRPCService] = "PullRequestsService" + attrMap[conventions.AttributeNetPeerIP] = "2600:1700:1f00:11c0:4de0:c223:a800:4e87" + attrMap[conventions.AttributeNetHostPort] = int64(8443) + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateGRPCServerAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeRPCService] = "PullRequestsService" + attrMap[conventions.AttributeNetPeerIP] = "192.168.1.70" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateInternalAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap["parameters"] = "account=7310,amount=1817.10" + attrMap[conventions.AttributeEnduserID] = "unittest" + return attrMap +} + +func generateMaxCountAttributes() map[string]interface{} { + attrMap := make(map[string]interface{}) + attrMap[conventions.AttributeHTTPMethod] = "POST" + attrMap[conventions.AttributeHTTPScheme] = "https" + attrMap[conventions.AttributeHTTPHost] = "api.opentelemetry.io" + attrMap[conventions.AttributeNetHostName] = "api22.opentelemetry.io" + attrMap[conventions.AttributeNetHostIP] = "2600:1700:1f00:11c0:1ced:afa5:fd88:9d48" + attrMap[conventions.AttributeNetHostPort] = int64(443) + attrMap[conventions.AttributeHTTPTarget] = "/blog/posts" + attrMap[conventions.AttributeHTTPFlavor] = "2" + attrMap[conventions.AttributeHTTPStatusCode] = int64(201) + attrMap[conventions.AttributeHTTPStatusText] = "Created" + attrMap[conventions.AttributeHTTPUserAgent] = + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36" + attrMap[conventions.AttributeHTTPRoute] = "/blog/posts" + attrMap[conventions.AttributeHTTPClientIP] = "2600:1700:1f00:11c0:1ced:afa5:fd77:9d01" + attrMap[conventions.AttributeNetPeerIP] = "2600:1700:1f00:11c0:1ced:afa5:fd77:9ddc" + attrMap[conventions.AttributeNetPeerPort] = int64(39111) + attrMap["ai-sampler.weight"] = float64(0.07) + attrMap["ai-sampler.absolute"] = false + attrMap["ai-sampler.maxhops"] = int64(6) + attrMap["application.create.location"] = "https://api.opentelemetry.io/blog/posts/806673B9-4F4D-4284-9635-3A3E3E3805BE" + attrMap["application.svcmap"] = "Blogosphere" + attrMap["application.abflags"] = "UIx=false,UI4=true,flow-alt3=false" + attrMap["application.thread"] = "proc-pool-14" + attrMap["application.session"] = "233CC260-63A8-4ACA-A1C1-8F97AB4A2C01" + attrMap["application.persist.size"] = int64(1172184) + attrMap["application.queue.size"] = int64(0) + attrMap["application.validation.results"] = "Success" + attrMap["application.job.id"] = "0E38800B-9C4C-484E-8F2B-C7864D854321" + attrMap["application.service.sla"] = float64(0.34) + attrMap["application.service.slo"] = float64(0.55) + attrMap[conventions.AttributeEnduserID] = "unittest" + attrMap[conventions.AttributeEnduserRole] = "poweruser" + attrMap[conventions.AttributeEnduserScope] = "email profile administrator" + return attrMap +} + +func generateSpanEvents(eventCnt PICTInputSpanChild) []*otlptrace.Span_Event { + if SpanChildCountNil == eventCnt { + return nil + } + listSize := calculateListSize(eventCnt) + eventList := make([]*otlptrace.Span_Event, listSize) + for i := 0; i < listSize; i++ { + eventList[i] = generateSpanEvent(i) + } + return eventList +} + +func generateSpanLinks(linkCnt PICTInputSpanChild, random io.Reader) []*otlptrace.Span_Link { + if SpanChildCountNil == linkCnt { + return nil + } + listSize := calculateListSize(linkCnt) + linkList := make([]*otlptrace.Span_Link, listSize) + for i := 0; i < listSize; i++ { + linkList[i] = generateSpanLink(i, random) + } + return linkList +} + +func calculateListSize(listCnt PICTInputSpanChild) int { + switch listCnt { + case SpanChildCountOne: + return 1 + case SpanChildCountTwo: + return 2 + case SpanChildCountEight: + return 8 + case SpanChildCountEmpty: + fallthrough + default: + return 0 + } +} + +func generateSpanEvent(index int) *otlptrace.Span_Event { + t := time.Now().Add(-75 * time.Microsecond) + return &otlptrace.Span_Event{ + TimeUnixNano: uint64(t.UnixNano()), + Name: "message", + Attributes: generateEventAttributes(index), + DroppedAttributesCount: 0, + } +} + +func generateEventAttributes(index int) []*otlpcommon.AttributeKeyValue { + attrMap := make(map[string]interface{}) + if index%2 == 0 { + attrMap[conventions.AttributeMessageType] = "SENT" + } else { + attrMap[conventions.AttributeMessageType] = "RECEIVED" + } + attrMap[conventions.AttributeMessageID] = int64(index) + attrMap[conventions.AttributeMessageCompressedSize] = int64(17 * index) + attrMap[conventions.AttributeMessageUncompressedSize] = int64(24 * index) + return convertMapToAttributeKeyValues(attrMap) +} + +func generateSpanLink(index int, random io.Reader) *otlptrace.Span_Link { + return &otlptrace.Span_Link{ + TraceId: generateTraceID(random), + SpanId: generateSpanID(random), + TraceState: "", + Attributes: generateLinkAttributes(index), + DroppedAttributesCount: 0, + } +} + +func generateLinkAttributes(index int) []*otlpcommon.AttributeKeyValue { + attrMap := generateMessagingConsumerAttributes() + return convertMapToAttributeKeyValues(attrMap) +} diff --git a/internal/goldendataset/span_generator_test.go b/internal/goldendataset/span_generator_test.go new file mode 100644 index 00000000000..c672400c2f9 --- /dev/null +++ b/internal/goldendataset/span_generator_test.go @@ -0,0 +1,78 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +import ( + "crypto/rand" + "testing" + + otlptrace "github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1" + "github.com/stretchr/testify/assert" +) + +func TestGenerateParentSpan(t *testing.T) { + random := rand.Reader + traceID := generateTraceID(random) + spanInputs := &PICTSpanInputs{ + Parent: SpanParentRoot, + Tracestate: TraceStateEmpty, + Kind: SpanKindServer, + Attributes: SpanAttrHTTPServer, + Events: SpanChildCountTwo, + Links: SpanChildCountOne, + Status: SpanStatusOk, + } + span := GenerateSpan(traceID, nil, "/gotest-parent", spanInputs, random) + assert.Equal(t, traceID, span.TraceId) + assert.Nil(t, span.ParentSpanId) + assert.Equal(t, 11, len(span.Attributes)) + assert.Equal(t, otlptrace.Status_Ok, span.Status.Code) +} + +func TestGenerateChildSpan(t *testing.T) { + random := rand.Reader + traceID := generateTraceID(random) + parentID := generateSpanID(random) + spanInputs := &PICTSpanInputs{ + Parent: SpanParentChild, + Tracestate: TraceStateEmpty, + Kind: SpanKindClient, + Attributes: SpanAttrDatabaseSQL, + Events: SpanChildCountEmpty, + Links: SpanChildCountNil, + Status: SpanStatusOk, + } + span := GenerateSpan(traceID, parentID, "get_test_info", spanInputs, random) + assert.Equal(t, traceID, span.TraceId) + assert.Equal(t, parentID, span.ParentSpanId) + assert.Equal(t, 8, len(span.Attributes)) + assert.Equal(t, otlptrace.Status_Ok, span.Status.Code) +} + +func TestGenerateSpans(t *testing.T) { + random := rand.Reader + count1 := 16 + spans, nextPos, err := GenerateSpans(count1, 0, "testdata/generated_pict_pairs_spans.txt", random) + assert.Nil(t, err) + assert.Equal(t, count1, len(spans)) + count2 := 256 + spans, nextPos, err = GenerateSpans(count2, nextPos, "testdata/generated_pict_pairs_spans.txt", random) + assert.Nil(t, err) + assert.Equal(t, count2, len(spans)) + count3 := 118 + spans, _, err = GenerateSpans(count3, nextPos, "testdata/generated_pict_pairs_spans.txt", random) + assert.Nil(t, err) + assert.Equal(t, count3, len(spans)) +} diff --git a/internal/goldendataset/testdata/generated_pict_pairs_spans.txt b/internal/goldendataset/testdata/generated_pict_pairs_spans.txt new file mode 100644 index 00000000000..61d1bae4452 --- /dev/null +++ b/internal/goldendataset/testdata/generated_pict_pairs_spans.txt @@ -0,0 +1,307 @@ +Parent Tracestate Kind Attributes Events Links Status +Child One Consumer FaaSDatasource Empty Nil AlreadyExists +Child Empty Unspecified gRPCClient Two One ResourceExhausted +Child Four Client gRPCClient Eight Eight DataLoss +Root Four Server FaaSHTTP One Empty ResourceExhausted +Child One Server FaaSOther Nil Two Unimplemented +Child One Unspecified HTTPClient Nil Eight InternalError +Root One Producer FaaSPubSub Two Empty Cancelled +Child One Client DatabaseSQL One One PermissionDenied +Child Four Unspecified FaaSTimer Empty Two FailedPrecondition +Child Empty Unspecified MessagingConsumer Eight Nil InvalidArgument +Root Empty Server FaaSTimer Two Eight AlreadyExists +Child One Internal Nil Eight Two ResourceExhausted +Child Empty Unspecified FaaSHTTP Nil Nil DeadlineExceeded +Child Empty Producer MessagingProducer Empty Empty Ok +Root Four Server HTTPServer Nil One Ok +Root Four Producer Empty One Nil OutOfRange +Child Empty Consumer FaaSDatasource One Two Unavailable +Child One Client gRPCClient Nil Empty OutOfRange +Child Empty Internal Internal One Eight FailedPrecondition +Root Empty Server FaaSTimer Eight One OutOfRange +Child Four Consumer FaaSDatasource Empty One Unauthenticated +Child Empty Client HTTPClient Two Nil DataLoss +Child Empty Unspecified FaaSPubSub Empty Two UnknownError +Child Four Client gRPCClient Two Two Ok +Child Four Unspecified HTTPClient Eight Empty Ok +Root One Server FaaSHTTP Empty Eight Aborted +Child One Client DatabaseNoSQL Nil One FailedPrecondition +Child Empty Client HTTPClient Empty One ResourceExhausted +Child Four Internal Nil Nil Empty AlreadyExists +Root Four Producer FaaSPubSub Eight One AlreadyExists +Child Four Client HTTPClient One Two InvalidArgument +Root One Server FaaSTimer Nil Nil UnknownError +Child Empty Unspecified HTTPServer One Two Cancelled +Child Four Server FaaSHTTP Eight One Cancelled +Child Empty Server FaaSTimer Nil Eight ResourceExhausted +Root One Server gRPCServer Nil Eight InvalidArgument +Child Four Unspecified gRPCServer Two Two Nil +Child One Consumer MessagingConsumer Nil Eight ResourceExhausted +Child One Unspecified MessagingProducer Two Nil FailedPrecondition +Child Four Consumer MessagingConsumer Two Empty Unavailable +Child One Producer FaaSPubSub One Nil Ok +Root Four Server MaxCount Empty Nil Cancelled +Root One Server HTTPServer Empty Eight DeadlineExceeded +Child One Consumer MessagingConsumer Empty Two FailedPrecondition +Child Empty Unspecified MaxCount Two One InvalidArgument +Child One Unspecified FaaSHTTP Two Two OutOfRange +Child Four Unspecified DatabaseSQL Eight Two Aborted +Child One Unspecified MaxCount Eight Eight UnknownError +Child Four Unspecified FaaSOther Eight Empty FailedPrecondition +Root One Server HTTPServer Eight Nil Unavailable +Root Empty Server MaxCount Nil Two Ok +Child Empty Consumer MessagingConsumer One One Aborted +Child One Client Empty Eight One Nil +Root Four Producer MessagingProducer Eight Eight PermissionDenied +Child Empty Internal Nil Empty Nil Nil +Child Empty Unspecified DatabaseNoSQL Two Two NotFound +Child Empty Client DatabaseSQL Nil Empty Nil +Child Four Producer FaaSPubSub Nil Eight ResourceExhausted +Child Empty Unspecified FaaSOther Two One DeadlineExceeded +Child Four Consumer FaaSDatasource Eight Empty InternalError +Root Empty Producer Empty Two Two ResourceExhausted +Root Four Server FaaSOther One Eight Nil +Child Four Internal Internal Two Nil PermissionDenied +Child One Client DatabaseSQL Empty Eight FailedPrecondition +Child Four Producer MessagingProducer One One InvalidArgument +Child Four Unspecified DatabaseNoSQL Empty Empty InvalidArgument +Child Four Unspecified DatabaseNoSQL One Nil ResourceExhausted +Child Empty Producer MessagingProducer Nil Nil Aborted +Child Empty Server gRPCServer Empty Empty Aborted +Child One Unspecified DatabaseNoSQL Eight One DataLoss +Root One Producer MessagingProducer Nil Two DataLoss +Root Four Producer FaaSPubSub Empty One FailedPrecondition +Child Four Client DatabaseNoSQL Empty Eight Unavailable +Child Four Consumer Nil One One NotFound +Root One Server Nil Two Eight DataLoss +Child Four Internal Internal Nil One UnknownError +Child One Producer FaaSPubSub Nil One Unavailable +Child Four Client DatabaseNoSQL Two Empty Unimplemented +Child One Unspecified FaaSOther Empty Empty UnknownError +Child One Client gRPCClient Empty Nil Nil +Child One Unspecified Internal Eight Two Nil +Child Four Unspecified FaaSDatasource Two Eight Ok +Child One Unspecified Empty Nil Empty Ok +Child One Consumer FaaSDatasource Empty Eight OutOfRange +Child Empty Consumer MessagingConsumer Eight One Unimplemented +Child Empty Unspecified Nil One Eight Unimplemented +Child Four Client gRPCClient One Nil Unimplemented +Child Empty Unspecified DatabaseSQL Two Nil Ok +Child One Client DatabaseNoSQL Nil Eight Unauthenticated +Child Four Internal Internal One Empty DeadlineExceeded +Child One Unspecified gRPCServer One Nil OutOfRange +Child Empty Unspecified MaxCount One Two AlreadyExists +Root Empty Server FaaSOther Nil Empty PermissionDenied +Child Four Internal Internal Empty Two InvalidArgument +Root Four Producer MessagingProducer Eight Two DeadlineExceeded +Root One Server FaaSOther Eight Nil NotFound +Child Empty Unspecified Nil Two One Unavailable +Child Four Internal Internal Nil Eight Ok +Child Four Producer Empty Empty Eight FailedPrecondition +Child One Server gRPCServer Eight One DeadlineExceeded +Child Four Consumer MessagingConsumer Two Nil Nil +Root Four Server gRPCServer Eight Two FailedPrecondition +Root Four Producer Empty Empty Nil Unavailable +Root Empty Server HTTPServer Two Empty Unauthenticated +Child Empty Unspecified FaaSHTTP One Empty DataLoss +Child Four Client DatabaseNoSQL One Nil DeadlineExceeded +Root One Producer FaaSPubSub Empty Nil Unimplemented +Root Empty Producer MessagingProducer One One InternalError +Child Empty Unspecified FaaSOther Two Empty AlreadyExists +Child Empty Unspecified DatabaseSQL Empty Nil ResourceExhausted +Child Four Unspecified gRPCClient Eight Nil Unauthenticated +Child Four Client HTTPClient Two Nil UnknownError +Child Four Unspecified HTTPServer Empty Two PermissionDenied +Root Four Producer MessagingProducer One Two AlreadyExists +Child One Unspecified HTTPClient Eight Two PermissionDenied +Child Four Consumer Nil Nil Two Ok +Child Empty Internal Internal Nil Empty NotFound +Child Four Unspecified FaaSDatasource Nil Two FailedPrecondition +Root One Server MaxCount Empty Empty InternalError +Child One Consumer Nil One Eight InvalidArgument +Child One Unspecified HTTPClient Empty Nil OutOfRange +Child Four Client HTTPClient Empty One DeadlineExceeded +Child Empty Client DatabaseSQL Nil Eight Cancelled +Child Four Internal Internal Nil Two Cancelled +Child Four Consumer MessagingConsumer Two Nil InternalError +Child Empty Consumer MessagingConsumer Eight Nil OutOfRange +Root Four Producer MessagingProducer Empty Two Unimplemented +Root One Server FaaSTimer One Empty InvalidArgument +Child Empty Client Empty Empty Eight NotFound +Child Four Unspecified FaaSOther Two Two InternalError +Child One Client DatabaseNoSQL One One Ok +Child One Unspecified MessagingConsumer One Empty Ok +Child Four Unspecified FaaSHTTP Two Empty NotFound +Root Empty Server FaaSTimer Empty Eight Unimplemented +Child One Unspecified FaaSPubSub Nil Nil PermissionDenied +Root Empty Server HTTPServer Eight Two InvalidArgument +Child Four Client HTTPClient One Two Unauthenticated +Child Empty Server gRPCServer One Nil InternalError +Root Empty Producer MessagingProducer Empty Eight OutOfRange +Child Four Producer MessagingProducer Eight Nil Nil +Child Empty Consumer FaaSDatasource Eight Empty Unimplemented +Child Empty Unspecified FaaSPubSub Empty Eight DataLoss +Child Four Unspecified MessagingConsumer Empty Empty AlreadyExists +Child Empty Producer FaaSPubSub One One NotFound +Child One Internal Internal Two Nil InternalError +Root Four Server FaaSTimer Nil One NotFound +Child Four Unspecified FaaSOther Nil One Unavailable +Child Empty Unspecified FaaSHTTP One Nil InternalError +Child Empty Unspecified gRPCServer Eight Nil AlreadyExists +Child One Client HTTPClient Nil One Unimplemented +Child One Client HTTPClient Empty Eight NotFound +Child Four Consumer FaaSDatasource One Eight UnknownError +Root Empty Producer MessagingProducer Two Two Unauthenticated +Child Empty Unspecified FaaSDatasource Two One Aborted +Child One Consumer MessagingConsumer Empty Nil DataLoss +Child One Consumer MessagingConsumer Eight One Cancelled +Child Empty Unspecified FaaSDatasource One Two DataLoss +Child Empty Client gRPCClient Empty Eight FailedPrecondition +Child Empty Unspecified Internal Eight Two ResourceExhausted +Child Empty Client gRPCClient One Nil InternalError +Child Empty Consumer Nil Two Nil PermissionDenied +Child Empty Producer FaaSPubSub One Eight OutOfRange +Child One Unspecified gRPCServer One Nil Ok +Child One Consumer FaaSDatasource One Empty DeadlineExceeded +Child One Unspecified FaaSDatasource Nil Eight NotFound +Child Empty Unspecified DatabaseNoSQL Empty Two PermissionDenied +Child One Unspecified FaaSHTTP Empty Empty UnknownError +Child Empty Server HTTPServer Empty One Aborted +Child Empty Unspecified HTTPClient Eight Eight Cancelled +Child Four Producer MessagingProducer One Empty Cancelled +Child Four Server MaxCount One Eight FailedPrecondition +Child Empty Internal Nil One Eight OutOfRange +Child One Unspecified gRPCServer Empty Two Cancelled +Child Four Server HTTPServer Nil Empty AlreadyExists +Child Four Unspecified Empty Two Two InvalidArgument +Root Empty Server HTTPServer Eight Two DataLoss +Child Empty Client gRPCClient Two Two Unavailable +Child Four Unspecified HTTPServer One One Nil +Child One Client gRPCClient Nil Eight DeadlineExceeded +Root One Server FaaSTimer Empty Eight Cancelled +Child Empty Consumer Nil Eight Eight Cancelled +Child Four Server FaaSTimer Eight Nil Ok +Root One Producer Empty Eight Empty UnknownError +Child One Client Empty Eight Nil AlreadyExists +Child Empty Internal Nil Eight Nil Unauthenticated +Child One Internal Nil Nil Eight DeadlineExceeded +Child One Producer Empty Two Two Cancelled +Child One Unspecified FaaSHTTP Eight Nil InvalidArgument +Child Empty Unspecified HTTPClient One One FailedPrecondition +Child One Unspecified HTTPServer Nil Empty ResourceExhausted +Child One Server Nil One Eight InternalError +Child Four Unspecified Empty Eight Nil Unauthenticated +Child Empty Unspecified MessagingConsumer Eight Two NotFound +Child Four Unspecified MaxCount Empty Eight NotFound +Child One Client gRPCClient One Two InvalidArgument +Child Four Unspecified DatabaseSQL Nil Empty InvalidArgument +Child Four Unspecified FaaSOther One Two OutOfRange +Child Empty Unspecified HTTPServer Two Nil FailedPrecondition +Child Empty Consumer FaaSDatasource Two Eight Nil +Child One Server FaaSTimer Nil One Aborted +Child Four Unspecified DatabaseNoSQL Two Empty UnknownError +Child Empty Server MaxCount Nil Nil OutOfRange +Child Four Unspecified FaaSTimer Nil Nil Unavailable +Child One Unspecified FaaSHTTP Eight Eight AlreadyExists +Child Empty Client DatabaseSQL Empty Eight UnknownError +Child One Producer Empty Eight Nil DeadlineExceeded +Child Empty Producer FaaSPubSub Empty One InternalError +Child Empty Unspecified gRPCClient Two One PermissionDenied +Child One Unspecified DatabaseSQL One Eight Unauthenticated +Child Four Client gRPCClient One Empty Cancelled +Child One Server MaxCount Empty Two Unimplemented +Child Empty Server Nil One Eight UnknownError +Root One Server gRPCServer Eight Eight DataLoss +Child Four Unspecified FaaSPubSub Two One Nil +Root One Server gRPCServer Nil Eight Unimplemented +Child One Server FaaSTimer Two Two Nil +Child Four Unspecified gRPCServer Two Eight Unauthenticated +Child Empty Server FaaSOther One Eight Unauthenticated +Child One Unspecified FaaSDatasource One Eight PermissionDenied +Child Empty Server Nil Two Two FailedPrecondition +Child One Unspecified Empty One Nil PermissionDenied +Child Four Internal Internal One Two Unimplemented +Child Empty Unspecified Empty Eight Two DataLoss +Child Empty Unspecified FaaSTimer Two Empty DeadlineExceeded +Child Empty Unspecified FaaSOther One Eight Aborted +Child One Unspecified FaaSOther One Nil ResourceExhausted +Child Empty Unspecified gRPCServer Two Nil PermissionDenied +Child Empty Unspecified MaxCount Eight Eight Aborted +Child One Consumer MessagingConsumer Two Nil Unauthenticated +Child Four Client Empty One One Unimplemented +Child Four Server MaxCount Two Eight PermissionDenied +Child One Unspecified FaaSDatasource Nil Nil ResourceExhausted +Child Empty Unspecified gRPCServer Eight Empty Unavailable +Child One Unspecified HTTPServer Nil One UnknownError +Child Four Internal Internal Nil Eight OutOfRange +Child One Unspecified FaaSOther One Nil Ok +Child Four Client DatabaseSQL Eight Two InternalError +Child Empty Unspecified DatabaseSQL One Eight NotFound +Child Empty Client DatabaseSQL One Nil OutOfRange +Child Four Server FaaSTimer Eight Empty Unauthenticated +Child Four Client DatabaseSQL One Nil AlreadyExists +Child Empty Unspecified HTTPServer Empty One InternalError +Root One Server MaxCount One One Nil +Child Four Unspecified MessagingProducer Two Nil ResourceExhausted +Child Four Client HTTPClient One Two Aborted +Child Empty Client DatabaseNoSQL Two Nil AlreadyExists +Child One Unspecified MaxCount Nil Empty DataLoss +Child One Internal Internal Empty Nil DataLoss +Child One Producer MessagingProducer One Two NotFound +Child One Unspecified FaaSTimer Two Two PermissionDenied +Root One Server FaaSOther Eight Empty Cancelled +Child Empty Client DatabaseSQL Empty One DeadlineExceeded +Child One Unspecified HTTPServer Two Eight Unimplemented +Child Four Client HTTPClient Nil Eight Nil +Root Empty Server MaxCount Nil Nil Unavailable +Child Four Internal Internal One One Aborted +Child One Unspecified FaaSHTTP Empty Nil PermissionDenied +Child One Unspecified FaaSHTTP Nil Two Unimplemented +Child One Unspecified MessagingConsumer Two Two PermissionDenied +Root One Server FaaSOther Nil Nil InvalidArgument +Child Empty Unspecified HTTPClient Empty Eight Unavailable +Child One Unspecified FaaSPubSub Eight Empty Unauthenticated +Child Empty Client gRPCClient Empty Empty AlreadyExists +Child One Unspecified DatabaseNoSQL One Empty InternalError +Root One Server FaaSHTTP One Empty Unauthenticated +Child Empty Server MaxCount Empty Empty ResourceExhausted +Child Four Client DatabaseSQL One Nil Unavailable +Root Four Server gRPCServer Nil Eight ResourceExhausted +Child Empty Internal Internal Nil Empty Unauthenticated +Child Four Unspecified HTTPServer Two Empty NotFound +Child Four Server MaxCount Two Eight Unauthenticated +Child Empty Unspecified MessagingConsumer Empty Two DeadlineExceeded +Child Four Client HTTPClient Two Two AlreadyExists +Child One Unspecified gRPCClient Nil Two NotFound +Child Empty Unspecified FaaSPubSub Nil Nil InvalidArgument +Child One Internal Internal Two Two AlreadyExists +Child Empty Consumer FaaSDatasource One Two InvalidArgument +Child Empty Server FaaSOther Nil Eight DataLoss +Child One Unspecified gRPCClient Nil Empty UnknownError +Child One Server Nil One Empty Aborted +Child Four Unspecified FaaSTimer One Two DataLoss +Child Empty Unspecified FaaSPubSub Empty One Aborted +Child One Unspecified FaaSHTTP Eight One Nil +Child One Client DatabaseSQL Eight Nil DataLoss +Child Empty Server HTTPServer Nil Eight OutOfRange +Child One Client gRPCClient Eight Two Aborted +Child One Unspecified DatabaseNoSQL Two Eight Nil +Child Four Client DatabaseNoSQL Eight Empty Aborted +Child Empty Internal Internal Eight One Unavailable +Child One Unspecified gRPCServer One Eight NotFound +Child Empty Unspecified FaaSHTTP One Two Ok +Child Four Unspecified gRPCServer One Empty UnknownError +Child Four Client DatabaseNoSQL One Nil Cancelled +Child Four Unspecified MessagingProducer Two Empty Unavailable +Child Empty Unspecified Empty Nil Eight Aborted +Child Four Server MaxCount Nil Nil DeadlineExceeded +Child Empty Client DatabaseSQL One Nil Unimplemented +Child Four Unspecified FaaSTimer Two Empty InternalError +Child Empty Unspecified DatabaseNoSQL One Eight OutOfRange +Root One Server FaaSHTTP Empty Empty Unavailable +Child One Unspecified FaaSDatasource Two Empty Cancelled +Child Empty Consumer MessagingConsumer Two One UnknownError +Child Empty Unspecified FaaSHTTP Two One FailedPrecondition +Child One Client Empty Two Nil InternalError +Root One Producer FaaSPubSub Eight Two DeadlineExceeded +Root One Producer MessagingProducer Empty Two UnknownError diff --git a/internal/goldendataset/testdata/generated_pict_pairs_traces.txt b/internal/goldendataset/testdata/generated_pict_pairs_traces.txt new file mode 100644 index 00000000000..59706ccec5e --- /dev/null +++ b/internal/goldendataset/testdata/generated_pict_pairs_traces.txt @@ -0,0 +1,29 @@ +Resource InstrumentationLibrary Spans +Nil None Several +Nil One One +Empty One None +K8sCloud None All +VMOnPrem Two All +Faas Two None +K8sOnPrem One Several +K8sOnPrem Two All +VMOnPrem None One +Faas One All +K8sCloud Two Several +Nil None None +K8sOnPrem None None +Faas None One +VMCloud One None +VMCloud Two All +Nil Two All +K8sCloud One None +K8sCloud Two One +VMCloud None One +Empty Two One +Faas One Several +VMOnPrem One None +K8sOnPrem One One +VMCloud None Several +Empty None All +Empty None Several +VMOnPrem Two Several diff --git a/internal/goldendataset/testdata/pict_input_spans.txt b/internal/goldendataset/testdata/pict_input_spans.txt new file mode 100644 index 00000000000..9430ce47e3e --- /dev/null +++ b/internal/goldendataset/testdata/pict_input_spans.txt @@ -0,0 +1,14 @@ +Parent: Root, Child +Tracestate: Empty, One, Four +Kind: Unspecified, Internal, Server, Client, Producer, Consumer +Attributes: Nil, Empty, DatabaseSQL, DatabaseNoSQL, FaaSDatasource, FaaSHTTP, FaaSPubSub, FaaSTimer, FaaSOther, HTTPClient, HTTPServer, MessagingProducer, MessagingConsumer, gRPCClient, gRPCServer, Internal, MaxCount +Events: Nil, Empty, One, Two, Eight +Links: Nil, Empty, One, Two, Eight +Status: Nil, Ok, Cancelled, UnknownError, InvalidArgument, DeadlineExceeded, NotFound, AlreadyExists, PermissionDenied, ResourceExhausted, FailedPrecondition, Aborted, OutOfRange, Unimplemented, InternalError, Unavailable, DataLoss, Unauthenticated + +IF [Parent] = "Root" THEN [Kind] in {"Server", "Producer"}; +IF [Kind] = "Internal" THEN [Attributes] in {"Nil", "Internal"}; +IF [Kind] = "Server" THEN [Attributes] in {"Nil", "FaaSHTTP", "FaaSTimer", "FaaSOther", "HTTPServer", "gRPCServer", "MaxCount"}; +IF [Kind] = "Client" THEN [Attributes] in {"Empty", "DatabaseSQL", "DatabaseNoSQL", "HTTPClient", "gRPCClient"}; +IF [Kind] = "Producer" THEN [Attributes] in {"Empty", "MessagingProducer", "FaaSPubSub"}; +IF [Kind] = "Consumer" THEN [Attributes] in {"Nil", "MessagingConsumer", "FaaSDatasource"}; diff --git a/internal/goldendataset/testdata/pict_input_traces.txt b/internal/goldendataset/testdata/pict_input_traces.txt new file mode 100644 index 00000000000..7e342474da7 --- /dev/null +++ b/internal/goldendataset/testdata/pict_input_traces.txt @@ -0,0 +1,3 @@ +Resource: Nil, Empty, VMOnPrem, VMCloud, K8sOnPrem, K8sCloud, Faas +InstrumentationLibrary: None, One, Two +Spans: None, One, Several, All diff --git a/internal/goldendataset/traces_generator.go b/internal/goldendataset/traces_generator.go new file mode 100644 index 00000000000..f499fb58be7 --- /dev/null +++ b/internal/goldendataset/traces_generator.go @@ -0,0 +1,139 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +import ( + "fmt" + "io" + + otlpcommon "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1" + otlptrace "github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1" +) + +//GenerateResourceSpans generates a slice of OTLP ResourceSpans objects based on the PICT-generated pairwise +//parameters defined in the parameters file specified by the tracePairsFile parameter. The pairs to generate +//spans for for defined in the file specified by the spanPairsFile parameter. The random parameter injects the +//random number generator to use in generating IDs and other random values. +//The slice of ResourceSpans are returned. If an err is returned, the slice elements will be nil. +func GenerateResourceSpans(tracePairsFile string, spanPairsFile string, + random io.Reader) ([]*otlptrace.ResourceSpans, error) { + pairsData, err := loadPictOutputFile(tracePairsFile) + if err != nil { + return nil, err + } + pairsTotal := len(pairsData) - 1 + spans := make([]*otlptrace.ResourceSpans, pairsTotal) + for index, values := range pairsData { + if index == 0 { + continue + } + tracingInputs := &PICTTracingInputs{ + Resource: PICTInputResource(values[TracesColumnResource]), + InstrumentationLibrary: PICTInputInstrumentationLibrary(values[TracesColumnInstrumentationLibrary]), + Spans: PICTInputSpans(values[TracesColumnSpans]), + } + rscSpan, spanErr := GenerateResourceSpan(tracingInputs, spanPairsFile, random) + if spanErr != nil { + err = spanErr + } + spans[index-1] = rscSpan + } + return spans, err +} + +//GenerateResourceSpan generates a single OTLP ResourceSpans populated based on the provided inputs. They are: +// tracingInputs - the pairwise combination of field value variations for this ResourceSpans +// spanPairsFile - the file with the PICT-generated parameter combinations to generate spans for +// random - the random number generator to use in generating ID values +// +//The generated resource spans. If err is not nil, some or all of the resource spans fields will be nil. +func GenerateResourceSpan(tracingInputs *PICTTracingInputs, spanPairsFile string, + random io.Reader) (*otlptrace.ResourceSpans, error) { + libSpans, err := generateLibrarySpansArray(tracingInputs, spanPairsFile, random) + return &otlptrace.ResourceSpans{ + Resource: GenerateResource(tracingInputs.Resource), + InstrumentationLibrarySpans: libSpans, + }, err +} + +func generateLibrarySpansArray(tracingInputs *PICTTracingInputs, spanPairsFile string, + random io.Reader) ([]*otlptrace.InstrumentationLibrarySpans, error) { + var count int + switch tracingInputs.InstrumentationLibrary { + case LibraryNone: + count = 1 + case LibraryOne: + count = 1 + case LibraryTwo: + count = 2 + } + var err error + libSpans := make([]*otlptrace.InstrumentationLibrarySpans, count) + for i := 0; i < count; i++ { + libSpans[i], err = generateLibrarySpans(tracingInputs, i, spanPairsFile, random) + } + return libSpans, err +} + +func generateLibrarySpans(tracingInputs *PICTTracingInputs, index int, spanPairsFile string, + random io.Reader) (*otlptrace.InstrumentationLibrarySpans, error) { + spanCaseCount, err := countTotalSpanCases(spanPairsFile) + if err != nil { + return nil, err + } + var spans []*otlptrace.Span + switch tracingInputs.Spans { + case LibrarySpansNone: + spans = make([]*otlptrace.Span, 0) + case LibrarySpansOne: + spans, _, err = GenerateSpans(1, 0, spanPairsFile, random) + case LibrarySpansSeveral: + spans, _, err = GenerateSpans(spanCaseCount/4, 0, spanPairsFile, random) + case LibrarySpansAll: + spans, _, err = GenerateSpans(spanCaseCount, 0, spanPairsFile, random) + default: + spans, _, err = GenerateSpans(16, 0, spanPairsFile, random) + } + return &otlptrace.InstrumentationLibrarySpans{ + InstrumentationLibrary: generateInstrumentationLibrary(tracingInputs, index), + Spans: spans, + }, err +} + +func countTotalSpanCases(spanPairsFile string) (int, error) { + pairsData, err := loadPictOutputFile(spanPairsFile) + if err != nil { + return 0, err + } + count := len(pairsData) - 1 + return count, err +} + +func generateInstrumentationLibrary(tracingInputs *PICTTracingInputs, + index int) *otlpcommon.InstrumentationLibrary { + if LibraryNone == tracingInputs.InstrumentationLibrary { + return nil + } + nameStr := fmt.Sprintf("%s-%s-%s-%d", tracingInputs.Resource, tracingInputs.InstrumentationLibrary, + tracingInputs.Spans, index) + verStr := "semver:1.1.7" + if index > 0 { + verStr = "" + } + return &otlpcommon.InstrumentationLibrary{ + Name: nameStr, + Version: verStr, + } +} diff --git a/internal/goldendataset/traces_generator_test.go b/internal/goldendataset/traces_generator_test.go new file mode 100644 index 00000000000..e742cb506ee --- /dev/null +++ b/internal/goldendataset/traces_generator_test.go @@ -0,0 +1,31 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goldendataset + +import ( + "io" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGenerateTraces(t *testing.T) { + random := io.Reader(rand.New(rand.NewSource(42))) + rscSpans, err := GenerateResourceSpans("testdata/generated_pict_pairs_traces.txt", + "testdata/generated_pict_pairs_spans.txt", random) + assert.Nil(t, err) + assert.Equal(t, 28, len(rscSpans)) +} diff --git a/translator/conventions/opentelemetry.go b/translator/conventions/opentelemetry.go index 298b0b28506..e2b55ed593d 100644 --- a/translator/conventions/opentelemetry.go +++ b/translator/conventions/opentelemetry.go @@ -15,18 +15,22 @@ package conventions // OpenTelemetry Semantic Convention values for Resource attribute names. -// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-resource-semantic-conventions.md +// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/resource/semantic_conventions/README.md const ( AttributeServiceName = "service.name" AttributeServiceNamespace = "service.namespace" AttributeServiceInstance = "service.instance.id" AttributeServiceVersion = "service.version" - AttributeLibraryName = "library.name" - AttributeLibraryLanguage = "library.language" - AttributeLibraryVersion = "library.version" + AttributeTelemetrySDKName = "telemetry.sdk.name" + AttributeTelemetrySDKLanguage = "telemetry.sdk.language" + AttributeTelemetrySDKVersion = "telemetry.sdk.version" AttributeContainerName = "container.name" AttributeContainerImage = "container.image.name" AttributeContainerTag = "container.image.tag" + AttributeFaasName = "faas.name" + AttributeFaasID = "faas.id" + AttributeFaasVersion = "faas.version" + AttributeFaasInstance = "faas.instance" AttributeK8sCluster = "k8s.cluster.name" AttributeK8sNamespace = "k8s.namespace.name" AttributeK8sPod = "k8s.pod.name" @@ -42,13 +46,10 @@ const ( AttributeCloudAccount = "cloud.account.id" AttributeCloudRegion = "cloud.region" AttributeCloudZone = "cloud.zone" - AttributeTelemetrySDKName = "telemetry.sdk.name" - AttributeTelemetrySDKLanguage = "telemetry.sdk.language" - AttributeTelemetrySDKVersion = "telemetry.sdk.version" ) // OpenTelemetry Semantic Convention values for general Span attribute names. -// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-span-general.md +// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/span-general.md const ( AttributeComponent = "component" AttributeNetTransport = "net.transport" @@ -71,7 +72,7 @@ const ( ) // OpenTelemetry Semantic Convention attribute names for HTTP related attributes -// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-http.md +// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md const ( AttributeHTTPMethod = "http.method" AttributeHTTPURL = "http.url" @@ -90,7 +91,7 @@ const ( ) // OpenTelemetry Semantic Convention attribute names for database related attributes -// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-database.md +// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/database.md const ( AttributeDBType = "db.type" AttributeDBInstance = "db.instance" @@ -100,7 +101,7 @@ const ( ) // OpenTelemetry Semantic Convention attribute names for gRPC related attributes -// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-rpc.md +// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/rpc.md const ( AttributeRPCService = "rpc.service" EventTypeMessage = "message" @@ -111,3 +112,38 @@ const ( AttributeMessageCompressedSize = "message.compressed_size" AttributeMessageUncompressedSize = "message.uncompressed_size" ) + +// OpenTelemetry Semantic Convention attribute names for FaaS related attributes +// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/faas.md +const ( + AttributeFaaSTrigger = "faas.trigger" + AttributeFaaSExecution = "faas.execution" + AttributeFaaSDocumentCollection = "faas.document.collection" + AttributeFaaSDocumentOperation = "faas.document.operation" + AttributeFaaSDocumentTime = "faas.document.time" + AttributeFaaSDocumentName = "faas.document.name" + AttributeFaaSTime = "faas.time" + AttributeFaaSCron = "faas.cron" + FaaSTriggerDataSource = "datasource" + FaaSTriggerHTTP = "http" + FaaSTriggerPubSub = "pubsub" + FaaSTriggerTimer = "timer" + FaaSTriggerOther = "other" +) + +// OpenTelemetry Semantic Convention attribute names for messaging system related attributes +// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/messaging.md +const ( + AttributeMessagingSystem = "messaging.system" + AttributeMessagingDestination = "messaging.destination" + AttributeMessagingDestinationKind = "messaging.destination_kind" + AttributeMessagingTempDestination = "messaging.temp_destination" + AttributeMessagingProtocol = "messaging.protocol" + AttributeMessagingProtocolVersion = "messaging.protocol_version" + AttributeMessagingURL = "messaging.url" + AttributeMessagingMessageID = "messaging.message_id" + AttributeMessagingConversationID = "messaging.conversation_id" + AttributeMessagingPayloadSize = "messaging.message_payload_size_bytes" + AttributeMessagingPayloadCompressedSize = "messaging.message_payload_compressed_size_bytes" + AttributeMessagingOperation = "messaging.operation" +) diff --git a/translator/internaldata/metrics_to_oc_test.go b/translator/internaldata/metrics_to_oc_test.go index 5ac491ccf24..b4c52481abc 100644 --- a/translator/internaldata/metrics_to_oc_test.go +++ b/translator/internaldata/metrics_to_oc_test.go @@ -38,8 +38,8 @@ func TestMetricsDataToOC(t *testing.T) { attrs.Upsert(conventions.AttributeHostHostname, pdata.NewAttributeValueString("host1")) attrs.Upsert(conventions.OCAttributeProcessID, pdata.NewAttributeValueInt(123)) attrs.Upsert(conventions.OCAttributeProcessStartTime, pdata.NewAttributeValueString("2020-02-11T20:26:00Z")) - attrs.Upsert(conventions.AttributeLibraryLanguage, pdata.NewAttributeValueString("CPP")) - attrs.Upsert(conventions.AttributeLibraryVersion, pdata.NewAttributeValueString("v2.0.1")) + attrs.Upsert(conventions.AttributeTelemetrySDKLanguage, pdata.NewAttributeValueString("CPP")) + attrs.Upsert(conventions.AttributeTelemetrySDKVersion, pdata.NewAttributeValueString("v2.0.1")) attrs.Upsert(conventions.OCAttributeExporterVersion, pdata.NewAttributeValueString("v1.2.0")) tests := []struct { diff --git a/translator/internaldata/oc_testdata_test.go b/translator/internaldata/oc_testdata_test.go index 2f528ac254f..9575cfd6eae 100644 --- a/translator/internaldata/oc_testdata_test.go +++ b/translator/internaldata/oc_testdata_test.go @@ -492,16 +492,16 @@ func generateResourceWithOcNodeAndResource() pdata.Resource { resource := pdata.NewResource() resource.InitEmpty() resource.Attributes().InitFromMap(map[string]pdata.AttributeValue{ - conventions.OCAttributeProcessStartTime: pdata.NewAttributeValueString("2020-02-11T20:26:00Z"), - conventions.AttributeHostHostname: pdata.NewAttributeValueString("host1"), - conventions.OCAttributeProcessID: pdata.NewAttributeValueInt(123), - conventions.AttributeLibraryVersion: pdata.NewAttributeValueString("v2.0.1"), - conventions.OCAttributeExporterVersion: pdata.NewAttributeValueString("v1.2.0"), - conventions.AttributeLibraryLanguage: pdata.NewAttributeValueString("CPP"), - conventions.OCAttributeResourceType: pdata.NewAttributeValueString("good-resource"), - "node-str-attr": pdata.NewAttributeValueString("node-str-attr-val"), - "resource-str-attr": pdata.NewAttributeValueString("resource-str-attr-val"), - "resource-int-attr": pdata.NewAttributeValueInt(123), + conventions.OCAttributeProcessStartTime: pdata.NewAttributeValueString("2020-02-11T20:26:00Z"), + conventions.AttributeHostHostname: pdata.NewAttributeValueString("host1"), + conventions.OCAttributeProcessID: pdata.NewAttributeValueInt(123), + conventions.AttributeTelemetrySDKVersion: pdata.NewAttributeValueString("v2.0.1"), + conventions.OCAttributeExporterVersion: pdata.NewAttributeValueString("v1.2.0"), + conventions.AttributeTelemetrySDKLanguage: pdata.NewAttributeValueString("CPP"), + conventions.OCAttributeResourceType: pdata.NewAttributeValueString("good-resource"), + "node-str-attr": pdata.NewAttributeValueString("node-str-attr-val"), + "resource-str-attr": pdata.NewAttributeValueString("resource-str-attr-val"), + "resource-int-attr": pdata.NewAttributeValueInt(123), }) return resource } diff --git a/translator/internaldata/oc_to_resource.go b/translator/internaldata/oc_to_resource.go index 56e0395a108..d6eca00a086 100644 --- a/translator/internaldata/oc_to_resource.go +++ b/translator/internaldata/oc_to_resource.go @@ -90,13 +90,13 @@ func ocNodeResourceToInternal(ocNode *occommon.Node, ocResource *ocresource.Reso } if ocNode.LibraryInfo != nil { if ocNode.LibraryInfo.CoreLibraryVersion != "" { - attrs.UpsertString(conventions.AttributeLibraryVersion, ocNode.LibraryInfo.CoreLibraryVersion) + attrs.UpsertString(conventions.AttributeTelemetrySDKVersion, ocNode.LibraryInfo.CoreLibraryVersion) } if ocNode.LibraryInfo.ExporterVersion != "" { attrs.UpsertString(conventions.OCAttributeExporterVersion, ocNode.LibraryInfo.ExporterVersion) } if ocNode.LibraryInfo.Language != occommon.LibraryInfo_LANGUAGE_UNSPECIFIED { - attrs.UpsertString(conventions.AttributeLibraryLanguage, ocNode.LibraryInfo.Language.String()) + attrs.UpsertString(conventions.AttributeTelemetrySDKLanguage, ocNode.LibraryInfo.Language.String()) } } } diff --git a/translator/internaldata/resource_to_oc.go b/translator/internaldata/resource_to_oc.go index 80cfcb7af2a..fb0a36e24b5 100644 --- a/translator/internaldata/resource_to_oc.go +++ b/translator/internaldata/resource_to_oc.go @@ -79,7 +79,7 @@ func internalResourceToOC(resource pdata.Resource) (*occommon.Node, *ocresource. ocNode.Identifier = &occommon.ProcessIdentifier{} } ocNode.Identifier.Pid = uint32(pid) - case conventions.AttributeLibraryVersion: + case conventions.AttributeTelemetrySDKVersion: if ocNode.LibraryInfo == nil { ocNode.LibraryInfo = &occommon.LibraryInfo{} } @@ -89,7 +89,7 @@ func internalResourceToOC(resource pdata.Resource) (*occommon.Node, *ocresource. ocNode.LibraryInfo = &occommon.LibraryInfo{} } ocNode.LibraryInfo.ExporterVersion = val - case conventions.AttributeLibraryLanguage: + case conventions.AttributeTelemetrySDKLanguage: if code, ok := occommon.LibraryInfo_Language_value[val]; ok { if ocNode.LibraryInfo == nil { ocNode.LibraryInfo = &occommon.LibraryInfo{}