-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OpenTelemetry instrumentation example (#296)
OTeL instrumentation example
- Loading branch information
Showing
9 changed files
with
279 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
### Steps to run this sample: | ||
1) Run a [Temporal service](https://github.com/temporalio/samples-go/tree/main/#how-to-use). | ||
|
||
One way could be just to use the Temporal CLI. | ||
|
||
```bash | ||
temporal server start-dev | ||
``` | ||
|
||
2) Run the following command to start the worker | ||
```bash | ||
go run opentelemetry/worker/main.go | ||
``` | ||
3) In another terminal, run the following command to run the workflow | ||
```bash | ||
go run opentelemetry/starter/main.go | ||
``` | ||
|
||
The example outputs the traces in the stdout, both the worker and the starter. | ||
|
||
If all is needed is to see Workflows and Activities there's no need to set up instrumentation for the Temporal cluster. | ||
|
||
In order to send the traces to a real service you need to replace | ||
|
||
```go | ||
exp, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) | ||
if err != nil { | ||
log.Fatalln("failed to initialize stdouttrace exporter", err) | ||
} | ||
``` | ||
with | ||
```go | ||
// Configure a new OTLP exporter using environment variables for sending data to Honeycomb over gRPC | ||
clientOTel := otlptracegrpc.NewClient() | ||
exp, err := otlptrace.New(ctx, clientOTel) | ||
if err != nil { | ||
log.Fatalf("failed to initialize exporter: %e", err) | ||
} | ||
``` | ||
|
||
And provide the required additional parameters like the OTLP endpoint. | ||
For many services that would mean just to set the standard OTeL env vars like: | ||
|
||
``` | ||
OTEL_SERVICE_NAME | ||
OTEL_EXPORTER_OTLP_ENDPOINT | ||
OTEL_EXPORTER_OTLP_HEADERS | ||
``` | ||
|
||
As an example this is what is the rendered by Honeycomb.io. | ||
|
||
![Honeycomb.io](honeycomb_traces.png) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package opentelemetry | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"go.opentelemetry.io/otel" | ||
"go.opentelemetry.io/otel/attribute" | ||
"go.opentelemetry.io/otel/trace" | ||
"go.temporal.io/sdk/activity" | ||
"go.temporal.io/sdk/workflow" | ||
) | ||
|
||
var tracer trace.Tracer | ||
|
||
func init() { | ||
// Name the tracer after the package, or the service if you are in main | ||
tracer = otel.Tracer("github.com/temporalio/samples-go/otel") | ||
} | ||
|
||
func Workflow(ctx workflow.Context, name string) error { | ||
logger := workflow.GetLogger(ctx) | ||
logger.Info("HelloWorld workflow started", "name", name) | ||
|
||
ctx = workflow.WithActivityOptions(ctx, workflow.ActivityOptions{ | ||
StartToCloseTimeout: 10 * time.Second, | ||
}) | ||
|
||
err := workflow.ExecuteActivity(ctx, Activity).Get(ctx, nil) | ||
|
||
if err != nil { | ||
logger.Error("Activity failed.", "Error", err) | ||
return err | ||
} | ||
|
||
logger.Info("HelloWorld workflow completed.") | ||
return nil | ||
} | ||
|
||
func Activity(ctx context.Context, name string) error { | ||
logger := activity.GetLogger(ctx) | ||
logger.Info("Activity", "name", name) | ||
|
||
// Get current span and add new attributes | ||
span := trace.SpanFromContext(ctx) | ||
span.SetAttributes(attribute.Bool("isTrue", true), attribute.String("stringAttr", "Ciao")) | ||
|
||
// Create a child span | ||
_, childSpan := tracer.Start(ctx, "custom-span") | ||
time.Sleep(1 * time.Second) | ||
childSpan.End() | ||
|
||
time.Sleep(1 * time.Second) | ||
|
||
// Add an event to the current span | ||
span.AddEvent("Done Activity") | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package opentelemetry | ||
|
||
import ( | ||
"go.opentelemetry.io/otel" | ||
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace" | ||
"go.opentelemetry.io/otel/propagation" | ||
"go.opentelemetry.io/otel/sdk/resource" | ||
sdktrace "go.opentelemetry.io/otel/sdk/trace" | ||
semconv "go.opentelemetry.io/otel/semconv/v1.17.0" | ||
) | ||
|
||
func InitializeGlobalTracerProvider() (*sdktrace.TracerProvider, error) { | ||
// Initialize tracer | ||
exp, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
tp := sdktrace.NewTracerProvider( | ||
sdktrace.WithBatcher(exp), | ||
sdktrace.WithResource(resource.NewWithAttributes( | ||
semconv.SchemaURL, | ||
semconv.ServiceName("temporal-example"), | ||
semconv.ServiceVersion("0.0.1"), | ||
)), | ||
) | ||
otel.SetTracerProvider(tp) | ||
|
||
otel.SetTextMapPropagator( | ||
propagation.NewCompositeTextMapPropagator( | ||
propagation.TraceContext{}, | ||
propagation.Baggage{}, | ||
), | ||
) | ||
|
||
return tp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"log" | ||
|
||
otelworkflow "github.com/temporalio/samples-go/opentelemetry" | ||
"go.temporal.io/sdk/client" | ||
"go.temporal.io/sdk/contrib/opentelemetry" | ||
"go.temporal.io/sdk/interceptor" | ||
) | ||
|
||
func main() { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
tp, err := otelworkflow.InitializeGlobalTracerProvider() | ||
if err != nil { | ||
log.Fatalln("Unable to create a global trace provider", err) | ||
} | ||
|
||
defer func() { | ||
if err := tp.Shutdown(ctx); err != nil { | ||
log.Println("Error shutting down trace provider:", err) | ||
} | ||
}() | ||
|
||
tracingInterceptor, err := opentelemetry.NewTracingInterceptor(opentelemetry.TracerOptions{}) | ||
if err != nil { | ||
log.Fatalln("Unable to create interceptor", err) | ||
} | ||
|
||
options := client.Options{ | ||
Interceptors: []interceptor.ClientInterceptor{tracingInterceptor}, | ||
} | ||
|
||
// The client is a heavyweight object that should be created once per process. | ||
c, err := client.Dial(options) | ||
if err != nil { | ||
log.Fatalln("Unable to create client", err) | ||
} | ||
defer c.Close() | ||
|
||
workflowOptions := client.StartWorkflowOptions{ | ||
ID: "otel_workflowID", | ||
TaskQueue: "otel", | ||
} | ||
|
||
we, err := c.ExecuteWorkflow(context.Background(), workflowOptions, otelworkflow.Workflow, "Temporal") | ||
if err != nil { | ||
log.Fatalln("Unable to execute workflow", err) | ||
} | ||
|
||
log.Println("Started workflow", "WorkflowID", we.GetID(), "RunID", we.GetRunID()) | ||
|
||
// Synchronously wait for the workflow completion. | ||
var result string | ||
err = we.Get(context.Background(), &result) | ||
if err != nil { | ||
log.Fatalln("Unable get workflow result", err) | ||
} | ||
log.Println("Workflow result:", result) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"log" | ||
|
||
otelworkflow "github.com/temporalio/samples-go/opentelemetry" | ||
"go.temporal.io/sdk/client" | ||
"go.temporal.io/sdk/contrib/opentelemetry" | ||
"go.temporal.io/sdk/interceptor" | ||
"go.temporal.io/sdk/worker" | ||
) | ||
|
||
func main() { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
tp, err := otelworkflow.InitializeGlobalTracerProvider() | ||
if err != nil { | ||
log.Fatalln("Unable to create a global trace provider", err) | ||
} | ||
|
||
defer func() { | ||
if err := tp.Shutdown(ctx); err != nil { | ||
log.Println("Error shutting down trace provider:", err) | ||
} | ||
}() | ||
|
||
tracingInterceptor, err := opentelemetry.NewTracingInterceptor(opentelemetry.TracerOptions{}) | ||
if err != nil { | ||
log.Fatalln("Unable to create interceptor", err) | ||
} | ||
|
||
options := client.Options{ | ||
Interceptors: []interceptor.ClientInterceptor{tracingInterceptor}, | ||
} | ||
|
||
// The client and worker are heavyweight objects that should be created once per process. | ||
c, err := client.Dial(options) | ||
if err != nil { | ||
log.Fatalln("Unable to create client", err) | ||
} | ||
defer c.Close() | ||
|
||
w := worker.New(c, "otel", worker.Options{}) | ||
|
||
w.RegisterWorkflow(otelworkflow.Workflow) | ||
w.RegisterActivity(otelworkflow.Activity) | ||
|
||
err = w.Run(worker.InterruptCh()) | ||
if err != nil { | ||
log.Fatalln("Worker run failed", err) | ||
} | ||
} |