exporter/zipkinexporter/zipkin.go (69 lines of code) (raw):
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package zipkinexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter"
import (
"bytes"
"context"
"fmt"
"net/http"
"github.com/openzipkin/zipkin-go/proto/zipkin_proto3"
zipkinreporter "github.com/openzipkin/zipkin-go/reporter"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/consumer/consumererror"
"go.opentelemetry.io/collector/pdata/ptrace"
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin/zipkinv2"
)
var translator zipkinv2.FromTranslator
// zipkinExporter is a multiplexing exporter that spawns a new OpenCensus-Go Zipkin
// exporter per unique node encountered. This is because serviceNames per node define
// unique services, alongside their IPs. Also it is useful to receive traffic from
// Zipkin servers and then transform them back to the final form when creating an
// OpenCensus spandata.
type zipkinExporter struct {
defaultServiceName string
url string
client *http.Client
serializer zipkinreporter.SpanSerializer
clientSettings *confighttp.ClientConfig
settings component.TelemetrySettings
}
func createZipkinExporter(cfg *Config, settings component.TelemetrySettings) (*zipkinExporter, error) {
ze := &zipkinExporter{
defaultServiceName: cfg.DefaultServiceName,
url: cfg.Endpoint,
clientSettings: &cfg.ClientConfig,
client: nil,
settings: settings,
}
switch cfg.Format {
case "json":
ze.serializer = zipkinreporter.JSONSerializer{}
case "proto":
ze.serializer = zipkin_proto3.SpanSerializer{}
default:
return nil, fmt.Errorf("%s is not one of json or proto", cfg.Format)
}
return ze, nil
}
// start creates the http client
func (ze *zipkinExporter) start(ctx context.Context, host component.Host) (err error) {
ze.client, err = ze.clientSettings.ToClient(ctx, host, ze.settings)
return
}
func (ze *zipkinExporter) pushTraces(ctx context.Context, td ptrace.Traces) error {
spans, err := translator.FromTraces(td)
if err != nil {
return consumererror.NewPermanent(fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err))
}
body, err := ze.serializer.Serialize(spans)
if err != nil {
return consumererror.NewPermanent(fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err))
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, ze.url, bytes.NewReader(body))
if err != nil {
return fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err)
}
req.Header.Set("Content-Type", ze.serializer.ContentType())
resp, err := ze.client.Do(req)
if err != nil {
return fmt.Errorf("failed to push trace data via Zipkin exporter: %w", err)
}
_ = resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return fmt.Errorf("failed the request with status code %d", resp.StatusCode)
}
return nil
}