Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions exporters/otlp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# OpenTelemetry Collector Go Exporter

[![GoDoc][godoc-image]][godoc-url]


This exporter converts OpenTelemetry [SpanData](https://github.com/open-telemetry/opentelemetry-go/blob/6769330394f78192df01cb59299e9e0f2e5e977b/sdk/export/trace/trace.go#L49)
to OpenTelemetry Protocol [Span](https://github.com/open-telemetry/opentelemetry-proto/blob/c20698d5bb483cf05de1a7c0e134b7c57e359674/opentelemetry/proto/trace/v1/trace.proto#L46)
and exports them to OpenTelemetry Collector.


## Installation

```bash
$ go get -u go.opentelemetry.io/otel/exporters/otlp
```

[godoc-url]: https://godoc.org/go.opentelemetry.io/otel/exporters/otlp

38 changes: 38 additions & 0 deletions exporters/otlp/alignment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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 otlp

import (
"os"
"testing"
"unsafe"

ottest "go.opentelemetry.io/otel/internal/testing"
)

// Ensure struct alignment prior to running tests.
func TestMain(m *testing.M) {
fields := []ottest.FieldOffset{
{
Name: "Exporter.lastConnectErrPtr",
Offset: unsafe.Offsetof(Exporter{}.lastConnectErrPtr),
},
}
if !ottest.Aligned8Byte(fields, os.Stderr) {
os.Exit(1)
}

os.Exit(m.Run())
}
113 changes: 113 additions & 0 deletions exporters/otlp/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// 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 otlp

import (
"math/rand"
"sync/atomic"
"time"
"unsafe"
)

func (e *Exporter) lastConnectError() error {
errPtr := (*error)(atomic.LoadPointer(&e.lastConnectErrPtr))
if errPtr == nil {
return nil
}
return *errPtr
}

func (e *Exporter) saveLastConnectError(err error) {
var errPtr *error
if err != nil {
errPtr = &err
}
atomic.StorePointer(&e.lastConnectErrPtr, unsafe.Pointer(errPtr))
}

func (e *Exporter) setStateDisconnected(err error) {
e.saveLastConnectError(err)
select {
case e.disconnectedCh <- true:
default:
}
}

func (e *Exporter) setStateConnected() {
e.saveLastConnectError(nil)
}

func (e *Exporter) connected() bool {
return e.lastConnectError() == nil
}

const defaultConnReattemptPeriod = 10 * time.Second

func (e *Exporter) indefiniteBackgroundConnection() {
defer func() {
e.backgroundConnectionDoneCh <- true
}()

connReattemptPeriod := e.c.reconnectionPeriod
if connReattemptPeriod <= 0 {
connReattemptPeriod = defaultConnReattemptPeriod
}

// No strong seeding required, nano time can
// already help with pseudo uniqueness.
rng := rand.New(rand.NewSource(time.Now().UnixNano() + rand.Int63n(1024)))

// maxJitterNanos: 70% of the connectionReattemptPeriod
maxJitterNanos := int64(0.7 * float64(connReattemptPeriod))

for {
// Otherwise these will be the normal scenarios to enable
// reconnection if we trip out.
// 1. If we've stopped, return entirely
// 2. Otherwise block until we are disconnected, and
// then retry connecting
select {
case <-e.stopCh:
return

case <-e.disconnectedCh:
// Normal scenario that we'll wait for
}

if err := e.connect(); err == nil {
e.setStateConnected()
} else {
e.setStateDisconnected(err)
}

// Apply some jitter to avoid lockstep retrials of other
// collector-exporters. Lockstep retrials could result in an
// innocent DDOS, by clogging the machine's resources and network.
jitter := time.Duration(rng.Int63n(maxJitterNanos))
select {
case <-e.stopCh:
return
case <-time.After(connReattemptPeriod + jitter):
}
}
}

func (e *Exporter) connect() error {
cc, err := e.dialToCollector()
if err != nil {
return err
}
return e.enableConnections(cc)
}
16 changes: 16 additions & 0 deletions exporters/otlp/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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 otlp contains an OpenTelemetry tracing exporter for OpenTelemetry Collector.
package otlp // import "go.opentelemetry.io/otel/exporters/otlp"
103 changes: 103 additions & 0 deletions exporters/otlp/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// 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 otlp_test

import (
"context"
"fmt"
"log"
"time"

"google.golang.org/grpc/credentials"

"go.opentelemetry.io/otel/api/global"
"go.opentelemetry.io/otel/exporters/otlp"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

func Example_insecure() {
exp, err := otlp.NewExporter(otlp.WithInsecure())
if err != nil {
log.Fatalf("Failed to create the collector exporter: %v", err)
}
defer func() {
_ = exp.Stop()
}()

tp, _ := sdktrace.NewProvider(
sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
sdktrace.WithBatcher(exp, // add following two options to ensure flush
sdktrace.WithScheduleDelayMillis(5),
sdktrace.WithMaxExportBatchSize(10),
))
if err != nil {
log.Fatalf("error creating trace provider: %v\n", err)
}

global.SetTraceProvider(tp)

tracer := global.TraceProvider().Tracer("test-tracer")

// Then use the OpenTelemetry tracing library, like we normally would.
ctx, span := tracer.Start(context.Background(), "CollectorExporter-Example")
defer span.End()

for i := 0; i < 10; i++ {
_, iSpan := tracer.Start(ctx, fmt.Sprintf("Sample-%d", i))
<-time.After(6 * time.Millisecond)
iSpan.End()
}
}

func Example_withTLS() {
// Please take at look at https://godoc.org/google.golang.org/grpc/credentials#TransportCredentials
// for ways on how to initialize gRPC TransportCredentials.
creds, err := credentials.NewClientTLSFromFile("my-cert.pem", "")
if err != nil {
log.Fatalf("failed to create gRPC client TLS credentials: %v", err)
}

exp, err := otlp.NewExporter(otlp.WithTLSCredentials(creds))
if err != nil {
log.Fatalf("failed to create the collector exporter: %v", err)
}
defer func() {
_ = exp.Stop()
}()

tp, err := sdktrace.NewProvider(
sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
sdktrace.WithBatcher(exp, // add following two options to ensure flush
sdktrace.WithScheduleDelayMillis(5),
sdktrace.WithMaxExportBatchSize(10),
))
if err != nil {
log.Fatalf("error creating trace provider: %v\n", err)
}

global.SetTraceProvider(tp)

tracer := global.TraceProvider().Tracer("test-tracer")

// Then use the OpenTelemetry tracing library, like we normally would.
ctx, span := tracer.Start(context.Background(), "Securely-Talking-To-Collector-Span")
defer span.End()

for i := 0; i < 10; i++ {
_, iSpan := tracer.Start(ctx, fmt.Sprintf("Sample-%d", i))
<-time.After(6 * time.Millisecond)
iSpan.End()
}
}
17 changes: 17 additions & 0 deletions exporters/otlp/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module go.opentelemetry.io/otel/exporters/otlp

replace go.opentelemetry.io/otel => ../..

require (
github.com/golang/protobuf v1.3.2
github.com/google/go-cmp v0.4.0
github.com/open-telemetry/opentelemetry-proto v0.0.0-20200219184922-5e1d5bc66d5a
github.com/stretchr/testify v1.4.0
go.opentelemetry.io/otel v0.2.3
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 // indirect
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect
golang.org/x/text v0.3.2 // indirect
google.golang.org/grpc v1.27.1
)

go 1.13
Loading