Skip to content

Commit c3866e0

Browse files
committed
echo upgrade + otel support
1 parent 9cb0e77 commit c3866e0

File tree

887 files changed

+152352
-12905
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

887 files changed

+152352
-12905
lines changed

cmd/root.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"context"
45
"fmt"
56
"log"
67
"os"
@@ -10,9 +11,13 @@ import (
1011
"gopkg.in/yaml.v2"
1112

1213
"github.com/appclacks/cabourotte/daemon"
13-
1414
"github.com/pkg/errors"
1515
"github.com/urfave/cli/v2"
16+
"go.opentelemetry.io/otel"
17+
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
18+
"go.opentelemetry.io/otel/sdk/resource"
19+
"go.opentelemetry.io/otel/sdk/trace"
20+
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
1621
"go.uber.org/zap"
1722
)
1823

@@ -56,6 +61,31 @@ func Main() {
5661
if err != nil {
5762
return errors.Wrapf(err, "Fail to start the logger")
5863
}
64+
ctx := context.Background()
65+
exp, err := otlptracehttp.New(ctx)
66+
if err != nil {
67+
return err
68+
}
69+
70+
r := resource.NewWithAttributes(
71+
semconv.SchemaURL,
72+
semconv.ServiceName("cabourotte"),
73+
)
74+
75+
shutdownFn := func() {}
76+
77+
if os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") != "" || os.Getenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") != "" {
78+
logger.Info("starting opentelemetry traces export")
79+
tracerProvider := trace.NewTracerProvider(trace.WithBatcher(exp), trace.WithResource(r))
80+
otel.SetTracerProvider(tracerProvider)
81+
shutdownFn = func() {
82+
err := tracerProvider.Shutdown(context.Background())
83+
if err != nil {
84+
panic(err)
85+
}
86+
}
87+
}
88+
defer shutdownFn()
5989
// nolint
6090
defer logger.Sync()
6191
daemonComponent, err := daemon.New(logger, &config)

daemon/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type Component struct {
3333
// New creates and start a new daemon component
3434
func New(logger *zap.Logger, config *Configuration) (*Component, error) {
3535
logger.Info("Starting the Cabourotte daemon")
36+
3637
prom, err := prometheus.New()
3738
if err != nil {
3839
return nil, err

discovery/http/root.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
package http
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"io"
78
"net"
89
"net/http"
10+
"net/http/httptrace"
911
"time"
1012

13+
"github.com/appclacks/cabourotte/healthcheck"
14+
"github.com/appclacks/cabourotte/tls"
1115
"github.com/pkg/errors"
1216
prom "github.com/prometheus/client_golang/prometheus"
17+
"go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace"
18+
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
19+
"go.opentelemetry.io/otel"
20+
"go.opentelemetry.io/otel/attribute"
21+
"go.opentelemetry.io/otel/codes"
1322
"go.uber.org/zap"
1423
"gopkg.in/tomb.v2"
15-
16-
"github.com/appclacks/cabourotte/healthcheck"
17-
"github.com/appclacks/cabourotte/tls"
1824
)
1925

2026
// HTTPDiscovery the http discovery struct
@@ -57,8 +63,13 @@ func New(logger *zap.Logger, config *Configuration, checkComponent *healthcheck.
5763
Config: config,
5864
URL: url,
5965
Client: &http.Client{
60-
Transport: transport,
61-
Timeout: time.Second * 5,
66+
Transport: otelhttp.NewTransport(
67+
transport,
68+
otelhttp.WithClientTrace(func(ctx context.Context) *httptrace.ClientTrace {
69+
return otelhttptrace.NewClientTrace(ctx)
70+
}),
71+
),
72+
Timeout: time.Second * 5,
6273
CheckRedirect: func(req *http.Request, via []*http.Request) error {
6374
return http.ErrUseLastResponse
6475
},
@@ -67,8 +78,8 @@ func New(logger *zap.Logger, config *Configuration, checkComponent *healthcheck.
6778
return &component, nil
6879
}
6980

70-
func (c *HTTPDiscovery) request() error {
71-
req, err := http.NewRequest("GET", c.URL, nil)
81+
func (c *HTTPDiscovery) request(ctx context.Context) error {
82+
req, err := http.NewRequestWithContext(ctx, "GET", c.URL, nil)
7283
if err != nil {
7384
return errors.Wrapf(err, "HTTP discovery: fail to create request for %s", c.URL)
7485
}
@@ -120,16 +131,26 @@ func (c *HTTPDiscovery) Start() error {
120131
for {
121132
select {
122133
case <-c.tick.C:
134+
tracer := otel.Tracer("discovery")
135+
ctx, span := tracer.Start(context.Background(), "discovery")
136+
span.SetAttributes(attribute.String("cabourotte.discovery.name", c.Config.Name))
137+
span.SetAttributes(attribute.String("cabourotte.discovery.type", "http"))
123138
c.Logger.Debug(fmt.Sprintf("HTTP discovery: polling %s", c.URL))
124139
start := time.Now()
125140
status := "success"
126-
err := c.request()
141+
err := c.request(ctx)
127142
duration := time.Since(start)
128143
if err != nil {
144+
span.RecordError(err)
145+
span.SetStatus(codes.Error, "discovery failure")
129146
status = "failure"
130147
msg := fmt.Sprintf("HTTP discovery error: %s", err.Error())
131148
c.Logger.Error(msg)
149+
} else {
150+
span.SetStatus(codes.Ok, "discovery successful")
132151
}
152+
span.SetAttributes(attribute.String("cabourotte.discovery.status", status))
153+
span.End()
133154
c.requestHistogram.With(prom.Labels{"name": c.Config.Name}).Observe(duration.Seconds())
134155
c.responseCounter.With(prom.Labels{"status": status, "name": c.Config.Name}).Inc()
135156
case <-c.t.Dying():

discovery/http/root_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package http
22

33
import (
4+
"context"
45
"encoding/json"
56
"net"
67
"net/http"
@@ -124,7 +125,7 @@ func TestRequest(t *testing.T) {
124125
if err != nil {
125126
t.Fatalf("Fail to create the HTTP discovery component :\n%v", err)
126127
}
127-
err = discovery.request()
128+
err = discovery.request(context.Background())
128129
if err != nil {
129130
t.Fatalf("HTTP discovery request failed\n%v", err)
130131
}
@@ -135,7 +136,7 @@ func TestRequest(t *testing.T) {
135136
if checks[0].Base().Name != "foo" {
136137
t.Fatalf("Invalid healthcheck name %s", checks[0].Base().Name)
137138
}
138-
err = discovery.request()
139+
err = discovery.request(context.Background())
139140
if err != nil {
140141
t.Fatalf("HTTP discovery request failed\n%v", err)
141142
}

exporter/http.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,21 @@ package exporter
22

33
import (
44
"bytes"
5+
"context"
56
"encoding/json"
67
"fmt"
78
"net"
89
"net/http"
10+
"net/http/httptrace"
911
"time"
1012

1113
"github.com/pkg/errors"
1214
"go.uber.org/zap"
1315

1416
"github.com/appclacks/cabourotte/healthcheck"
1517
"github.com/appclacks/cabourotte/tls"
18+
"go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace"
19+
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
1620
)
1721

1822
// HTTPConfiguration The configuration for the HTTP exporter.
@@ -86,8 +90,13 @@ func NewHTTPExporter(logger *zap.Logger, config *HTTPConfiguration) (*HTTPExport
8690
Config: config,
8791
URL: url,
8892
Client: &http.Client{
89-
Transport: transport,
90-
Timeout: time.Second * 3,
93+
Transport: otelhttp.NewTransport(
94+
transport,
95+
otelhttp.WithClientTrace(func(ctx context.Context) *httptrace.ClientTrace {
96+
return otelhttptrace.NewClientTrace(ctx)
97+
}),
98+
),
99+
Timeout: time.Second * 3,
91100
CheckRedirect: func(req *http.Request, via []*http.Request) error {
92101
return http.ErrUseLastResponse
93102
},
@@ -134,14 +143,14 @@ func (c *HTTPExporter) GetConfig() interface{} {
134143
}
135144

136145
// Push pushes events to the HTTP destination
137-
func (c *HTTPExporter) Push(result *healthcheck.Result) error {
146+
func (c *HTTPExporter) Push(ctx context.Context, result *healthcheck.Result) error {
138147
var jsonBytes []byte
139148
payload := []*healthcheck.Result{result}
140149
jsonBytes, err := json.Marshal(payload)
141150
if err != nil {
142151
return errors.Wrapf(err, "Fail to convert result to json:\n%v", result)
143152
}
144-
req, err := http.NewRequest("POST", c.URL, bytes.NewBuffer(jsonBytes))
153+
req, err := http.NewRequestWithContext(ctx, "POST", c.URL, bytes.NewBuffer(jsonBytes))
145154
if err != nil {
146155
return errors.Wrapf(err, "HTTP exporter: fail to create request for %s", c.URL)
147156
}

exporter/http_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package exporter
22

33
import (
4+
"context"
45
"net/http"
56
"net/http/httptest"
67
"strconv"
@@ -39,7 +40,7 @@ func TestHTTPExporter(t *testing.T) {
3940
if err != nil {
4041
t.Fatalf("Fail to start the http exporter:\n%v", err)
4142
}
42-
err = exporter.Push(&healthcheck.Result{
43+
err = exporter.Push(context.Background(), &healthcheck.Result{
4344
Name: "foo",
4445
Success: true,
4546
HealthcheckTimestamp: time.Now().Unix(),

exporter/riemann.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package exporter
22

33
import (
4+
"context"
45
"fmt"
56
"net"
67
"time"
@@ -145,7 +146,7 @@ func (c *RiemannExporter) IsStarted() bool {
145146
}
146147

147148
// Push pushes events to the desination
148-
func (c *RiemannExporter) Push(result *healthcheck.Result) error {
149+
func (c *RiemannExporter) Push(_ context.Context, result *healthcheck.Result) error {
149150
state := "ok"
150151
if !result.Success {
151152
state = "critical"

exporter/root.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
package exporter
22

33
import (
4+
"context"
45
"fmt"
56
"sync"
67
"time"
78

9+
"github.com/appclacks/cabourotte/healthcheck"
10+
"github.com/appclacks/cabourotte/memorystore"
11+
"github.com/appclacks/cabourotte/prometheus"
812
"github.com/pkg/errors"
913
prom "github.com/prometheus/client_golang/prometheus"
14+
"go.opentelemetry.io/otel"
15+
"go.opentelemetry.io/otel/attribute"
16+
"go.opentelemetry.io/otel/codes"
1017
"go.uber.org/zap"
1118
"gopkg.in/tomb.v2"
12-
13-
"github.com/appclacks/cabourotte/healthcheck"
14-
"github.com/appclacks/cabourotte/memorystore"
15-
"github.com/appclacks/cabourotte/prometheus"
1619
)
1720

1821
// Exporter the exporter interface
@@ -23,7 +26,7 @@ type Exporter interface {
2326
IsStarted() bool
2427
Name() string
2528
GetConfig() interface{}
26-
Push(*healthcheck.Result) error
29+
Push(context.Context, *healthcheck.Result) error
2730
}
2831

2932
// Component the exporter component
@@ -122,7 +125,9 @@ func (c *Component) Start() error {
122125
})
123126
go func() {
124127
defer c.wg.Done()
128+
tracer := otel.Tracer("exporter")
125129
for message := range c.ChanResult {
130+
ctx, span := tracer.Start(context.Background(), "export")
126131
c.MemoryStore.Add(message)
127132
if message.Success {
128133
c.Logger.Debug("Healthcheck successful",
@@ -140,21 +145,28 @@ func (c *Component) Start() error {
140145
}
141146
for k := range c.Exporters {
142147
exporter := c.Exporters[k]
148+
ctx, exporterSpan := tracer.Start(ctx, "exporter")
149+
exporterSpan.SetAttributes(attribute.String("cabourotte.exporter.name", exporter.Name()))
143150
if exporter.IsStarted() {
144151
start := time.Now()
145-
err := exporter.Push(message)
152+
err := exporter.Push(ctx, message)
146153
duration := time.Since(start)
147154
status := "success"
148155
name := exporter.Name()
149156
if err != nil {
150157
c.Logger.Error(fmt.Sprintf("Failed to push healthchecks result for exporter %s: %s", name, err.Error()))
151158
status = "failure"
159+
exporterSpan.RecordError(err)
160+
exporterSpan.SetStatus(codes.Error, "exporter failure")
152161
err := exporter.Stop()
153162
if err != nil {
154163
// do not return error
155164
// on purpose
165+
exporterSpan.RecordError(err)
156166
c.Logger.Error(fmt.Sprintf("Fail to close the exporter %s: %s", name, err.Error()))
157167
}
168+
} else {
169+
span.SetStatus(codes.Ok, "successfully exported results")
158170
}
159171
c.exporterHistogram.With(prom.Labels{"name": name, "status": status}).Observe(duration.Seconds())
160172
}
@@ -163,10 +175,13 @@ func (c *Component) Start() error {
163175
if err != nil {
164176
// do not return error
165177
// on purpose
178+
exporterSpan.SetStatus(codes.Error, "exporter failure")
179+
span.RecordError(err)
166180
c.Logger.Error(fmt.Sprintf("fail to reconnect the exporter %s: %s", exporter.Name(), err.Error()))
167181
}
168182
}
169183
}
184+
span.End()
170185
}
171186
c.Logger.Info("Exporter routine stopped")
172187

0 commit comments

Comments
 (0)