zipkin.go 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package zipkinexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter"
  4. import (
  5. "bytes"
  6. "context"
  7. "fmt"
  8. "net/http"
  9. "github.com/openzipkin/zipkin-go/proto/zipkin_proto3"
  10. zipkinreporter "github.com/openzipkin/zipkin-go/reporter"
  11. "go.opentelemetry.io/collector/component"
  12. "go.opentelemetry.io/collector/config/confighttp"
  13. "go.opentelemetry.io/collector/consumer/consumererror"
  14. "go.opentelemetry.io/collector/pdata/ptrace"
  15. "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin/zipkinv2"
  16. )
  17. var translator zipkinv2.FromTranslator
  18. // zipkinExporter is a multiplexing exporter that spawns a new OpenCensus-Go Zipkin
  19. // exporter per unique node encountered. This is because serviceNames per node define
  20. // unique services, alongside their IPs. Also it is useful to receive traffic from
  21. // Zipkin servers and then transform them back to the final form when creating an
  22. // OpenCensus spandata.
  23. type zipkinExporter struct {
  24. defaultServiceName string
  25. url string
  26. client *http.Client
  27. serializer zipkinreporter.SpanSerializer
  28. clientSettings *confighttp.HTTPClientSettings
  29. settings component.TelemetrySettings
  30. }
  31. func createZipkinExporter(cfg *Config, settings component.TelemetrySettings) (*zipkinExporter, error) {
  32. ze := &zipkinExporter{
  33. defaultServiceName: cfg.DefaultServiceName,
  34. url: cfg.Endpoint,
  35. clientSettings: &cfg.HTTPClientSettings,
  36. client: nil,
  37. settings: settings,
  38. }
  39. switch cfg.Format {
  40. case "json":
  41. ze.serializer = zipkinreporter.JSONSerializer{}
  42. case "proto":
  43. ze.serializer = zipkin_proto3.SpanSerializer{}
  44. default:
  45. return nil, fmt.Errorf("%s is not one of json or proto", cfg.Format)
  46. }
  47. return ze, nil
  48. }
  49. // start creates the http client
  50. func (ze *zipkinExporter) start(_ context.Context, host component.Host) (err error) {
  51. ze.client, err = ze.clientSettings.ToClient(host, ze.settings)
  52. return
  53. }
  54. func (ze *zipkinExporter) pushTraces(ctx context.Context, td ptrace.Traces) error {
  55. spans, err := translator.FromTraces(td)
  56. if err != nil {
  57. return consumererror.NewPermanent(fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err))
  58. }
  59. body, err := ze.serializer.Serialize(spans)
  60. if err != nil {
  61. return consumererror.NewPermanent(fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err))
  62. }
  63. req, err := http.NewRequestWithContext(ctx, "POST", ze.url, bytes.NewReader(body))
  64. if err != nil {
  65. return fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err)
  66. }
  67. req.Header.Set("Content-Type", ze.serializer.ContentType())
  68. resp, err := ze.client.Do(req)
  69. if err != nil {
  70. return fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err)
  71. }
  72. _ = resp.Body.Close()
  73. if resp.StatusCode < 200 || resp.StatusCode > 299 {
  74. return fmt.Errorf("failed the request with status code %d", resp.StatusCode)
  75. }
  76. return nil
  77. }