You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	Export resource attributes from zipkin exporter (#2589)
* Export resource attributes from zipkin exporter * Update CHANGELOG.md Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> * Refactoring * Refactoring Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
		| @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm | ||||
| ### Changed | ||||
|  | ||||
| - Jaeger exporter takes into additional 70 bytes overhead into consideration when sending UDP packets (#2489, #2512) | ||||
| - Zipkin exporter exports `Resource` attributes as the `Tags` field. (#2589) | ||||
|  | ||||
| ### Deprecated | ||||
|  | ||||
|   | ||||
| @@ -168,6 +168,27 @@ func attributesToJSONMapString(attributes []attribute.KeyValue) string { | ||||
| 	return (string)(jsonBytes) | ||||
| } | ||||
|  | ||||
| // attributeToStringPair serializes each attribute to a string pair | ||||
| func attributeToStringPair(kv attribute.KeyValue) (string, string) { | ||||
| 	switch kv.Value.Type() { | ||||
| 	// For slice attributes, serialize as JSON list string. | ||||
| 	case attribute.BOOLSLICE: | ||||
| 		json, _ := json.Marshal(kv.Value.AsBoolSlice()) | ||||
| 		return (string)(kv.Key), (string)(json) | ||||
| 	case attribute.INT64SLICE: | ||||
| 		json, _ := json.Marshal(kv.Value.AsInt64Slice()) | ||||
| 		return (string)(kv.Key), (string)(json) | ||||
| 	case attribute.FLOAT64SLICE: | ||||
| 		json, _ := json.Marshal(kv.Value.AsFloat64Slice()) | ||||
| 		return (string)(kv.Key), (string)(json) | ||||
| 	case attribute.STRINGSLICE: | ||||
| 		json, _ := json.Marshal(kv.Value.AsStringSlice()) | ||||
| 		return (string)(kv.Key), (string)(json) | ||||
| 	default: | ||||
| 		return (string)(kv.Key), kv.Value.Emit() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // extraZipkinTags are those that may be added to every outgoing span | ||||
| var extraZipkinTags = []string{ | ||||
| 	"otel.status_code", | ||||
| @@ -177,25 +198,15 @@ var extraZipkinTags = []string{ | ||||
|  | ||||
| func toZipkinTags(data tracesdk.ReadOnlySpan) map[string]string { | ||||
| 	attr := data.Attributes() | ||||
| 	m := make(map[string]string, len(attr)+len(extraZipkinTags)) | ||||
| 	resourceAttr := data.Resource().Attributes() | ||||
| 	m := make(map[string]string, len(attr)+len(resourceAttr)+len(extraZipkinTags)) | ||||
| 	for _, kv := range attr { | ||||
| 		switch kv.Value.Type() { | ||||
| 		// For slice attributes, serialize as JSON list string. | ||||
| 		case attribute.BOOLSLICE: | ||||
| 			json, _ := json.Marshal(kv.Value.AsBoolSlice()) | ||||
| 			m[(string)(kv.Key)] = (string)(json) | ||||
| 		case attribute.INT64SLICE: | ||||
| 			json, _ := json.Marshal(kv.Value.AsInt64Slice()) | ||||
| 			m[(string)(kv.Key)] = (string)(json) | ||||
| 		case attribute.FLOAT64SLICE: | ||||
| 			json, _ := json.Marshal(kv.Value.AsFloat64Slice()) | ||||
| 			m[(string)(kv.Key)] = (string)(json) | ||||
| 		case attribute.STRINGSLICE: | ||||
| 			json, _ := json.Marshal(kv.Value.AsStringSlice()) | ||||
| 			m[(string)(kv.Key)] = (string)(json) | ||||
| 		default: | ||||
| 			m[(string)(kv.Key)] = kv.Value.Emit() | ||||
| 		} | ||||
| 		k, v := attributeToStringPair(kv) | ||||
| 		m[k] = v | ||||
| 	} | ||||
| 	for _, kv := range resourceAttr { | ||||
| 		k, v := attributeToStringPair(kv) | ||||
| 		m[k] = v | ||||
| 	} | ||||
|  | ||||
| 	if data.Status().Code != codes.Unset { | ||||
|   | ||||
| @@ -39,6 +39,9 @@ import ( | ||||
| func TestModelConversion(t *testing.T) { | ||||
| 	resource := resource.NewSchemaless( | ||||
| 		semconv.ServiceNameKey.String("model-test"), | ||||
| 		semconv.ServiceVersionKey.String("0.1.0"), | ||||
| 		attribute.Int64("resource-attr1", 42), | ||||
| 		attribute.IntSlice("resource-attr2", []int{0, 1, 2}), | ||||
| 	) | ||||
|  | ||||
| 	inputBatch := tracetest.SpanStubs{ | ||||
| @@ -408,6 +411,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"attr3":            "[0,1,2]", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data with no parent | ||||
| @@ -447,6 +454,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"attr2":            "bar", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data of unspecified kind | ||||
| @@ -486,6 +497,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"attr2":            "bar", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data of internal kind | ||||
| @@ -525,6 +540,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"attr2":            "bar", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data of client kind | ||||
| @@ -570,6 +589,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"peer.hostname":    "test-peer-hostname", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data of producer kind | ||||
| @@ -609,6 +632,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"attr2":            "bar", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data of consumer kind | ||||
| @@ -648,6 +675,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"attr2":            "bar", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data with no events | ||||
| @@ -678,6 +709,10 @@ func TestModelConversion(t *testing.T) { | ||||
| 				"attr2":            "bar", | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "model-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 				"resource-attr1":   "42", | ||||
| 				"resource-attr2":   "[0,1,2]", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model for span data with an "error" attribute set to "false" | ||||
| @@ -712,7 +747,12 @@ func TestModelConversion(t *testing.T) { | ||||
| 					Value:     "ev2", | ||||
| 				}, | ||||
| 			}, | ||||
| 			Tags: nil, // should be omitted | ||||
| 			Tags: map[string]string{ | ||||
| 				"service.name":    "model-test", | ||||
| 				"service.version": "0.1.0", | ||||
| 				"resource-attr1":  "42", | ||||
| 				"resource-attr2":  "[0,1,2]", | ||||
| 			}, // only resource tags should be included | ||||
| 		}, | ||||
| 	} | ||||
| 	gottenOutputBatch := SpanModels(inputBatch) | ||||
|   | ||||
| @@ -200,6 +200,7 @@ func logStoreLogger(s *logStore) *log.Logger { | ||||
| func TestExportSpans(t *testing.T) { | ||||
| 	resource := resource.NewSchemaless( | ||||
| 		semconv.ServiceNameKey.String("exporter-test"), | ||||
| 		semconv.ServiceVersionKey.String("0.1.0"), | ||||
| 	) | ||||
|  | ||||
| 	spans := tracetest.SpanStubs{ | ||||
| @@ -271,6 +272,8 @@ func TestExportSpans(t *testing.T) { | ||||
| 			Tags: map[string]string{ | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "404, file not found", | ||||
| 				"service.name":     "exporter-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 			}, | ||||
| 		}, | ||||
| 		// model of child | ||||
| @@ -299,6 +302,8 @@ func TestExportSpans(t *testing.T) { | ||||
| 			Tags: map[string]string{ | ||||
| 				"otel.status_code": "Error", | ||||
| 				"error":            "403, forbidden", | ||||
| 				"service.name":     "exporter-test", | ||||
| 				"service.version":  "0.1.0", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user