OpenTelemetry is an open-source framework which provides libraries, agents, and other components for users to measure and collect service and software performance data. It enables development workflows to utilize standardized and interoperable observability pipelines across various platforms, teams, and even programming languages.
Instrumenting Golang with OpenTelemetry provides users with robust tools to generate, collect, and export telemetry data from your Go applications. OTel easily integrates with Golang to manage traces, record operational metrics, and log application performance and behavior. OpenTelemetry uses Go’s lightweight SDK to capture all relevant real-time application and performance data, giving you insights into how well your Go program is running.
OTel simplifies monitoring and issue diagnosis, aided by its libraries and tools which seamlessly integrate into your systems. This lets you understand on a deeper level your distributed system’s behavior, performance, and resource utilization, helping you to troubleshoot your software to improve system function and reliability.
Continue reading to learn how to instrument a Golang app using OpenTelemetry, along with some best practices to ensure you configure it correctly.
Key Takeaways
- Instrumenting Golang apps allows you to monitor and troubleshoot memory, CPU, and network usage issues.
- The system in question must be observable – in other words, its components must emit log, metric, and trace data.
- Instrumenting Golang apps with OpenTelemetry ensures the system’s metrics and traces are captured.
- Go must be installed before integrating OpenTelemetry into its applications.
- Instrument critical software operations via latency, error rate, and application-specific attribute data, especially operations which are prone to slowing or obstructing performance levels.
A Complete Guide on How to Instrument a Golang App Using OpenTelemetry
Instrumenting Golang applications enables the monitoring and troubleshooting of errors related to memory usage, CPU load, and network activity. This aids in detecting errors proactively, allowing for timely interventions and swift fixes that prevent issues from escalating.
Here are the primary reasons to monitor and troubleshoot your Go applications:
- Enhanced Observability – Achieve detailed, real-time insights into application performance and interactions.
- Proactive Troubleshooting – Detect and diagnose issues early on, to avoid negative impact on user experience.
- Performance Optimization – Pinpoint and resolve performance bottlenecks to boost efficiency and scalability.
- Effective Incident Management – Swiftly navigate and resolve issues via comprehensive trace and log data.
- Informed Decisions – Utilize metrics to make well-informed decisions regarding infrastructure and scalability.
- Compliance and Security – Ensure system security and compliance by monitoring and logging system access and modifications.
Side Note
To make a system observable, you must ensure that its code emits trace, log, and metric data. OpenTelemetry allows for this in two primary ways:
- Code-based solutions via official APIs and SDKs, for most languages (deeper insight and rich telemetry from your application itself)
- Zero-code solutions typically through environment variables and other language-specific mechanisms, which generates detailed telemetry from the libraries you use and the environment in which your application runs.
Keep reading to learn in detail how to instrument a Go application using OpenTelemetry.
7 Steps on Instrumenting Golang Using OpenTelemetry
Instrumenting Golang apps with OpenTelemetry allows you to capture telemetry data, in particular metrics and traces, from your Golang code. Follow the step-by-step instructions below to instrument your Golang apps using OpenTelemetry.
Note
Auto-instrumentation of the Golang app eliminates the need for developers to manually add tracing or monitoring code to their applications. With this feature, you can add instrumentation to your codebase dynamically.
Step 1: Set up your Project Environment
Before integrating OpenTelemetry into your Go applications, the Go programming language must be appropriately set up on your system. If you haven’t installed Go yet, follow the installation instructions in the official Go documentation.
After successfully installing Go, verify its installation to ensure everything is configured correctly. To do this, open a new terminal window and execute the command go version. This command will show your current Go version, confirming that the installation was successful and that your development environment is ready.
Step 2: Create and Launch an HTTP Server
In this step, you’ll craft an HTTP server using Go, forming the backbone for integrating OpenTelemetry.
Begin by creating a new file named main.go. In this file, write code to establish a primary HTTP server configured to listen on port 8080. Specifically, your server should handle incoming requests to the /spinwheel URL path.
The server you create should respond to “Hello, OpenTelemetry!” whenever accessed. To start your server, run the command go run main.go from your terminal. Once the server runs, open your web browser and navigate to http://<YOUR IP>:8080 to view the server’s response.
This simple server setup is a practical introduction to web server operations in Go and a foundation for further OpenTelemetry implementation. Here’s what the main.go file should look like:
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/spinwheel", spinwheel)
log.Fatal(http.ListenAndServe(":8080", nil))
}
It’s also necessary to configure the behavior of your /spinwheel handler in a separate file named spinwheel.go. In this file, implement a function that generates a random number from 1 to 12, mimicking the action of a spinning wheel of fortune. The function should then return this result to the client. This setup helps modularize your code, allowing for more apparent organization and easier maintenance.
package main
import (
"io"
"log"
"math/rand"
"net/http"
"strconv"
)
func spinwheel(w http.ResponseWriter, r *http.Request) {
roll := 1 + rand.Intn(12)
resp := strconv.Itoa(roll) + "\n"
if _, err := io.WriteString(w, resp); err != nil {
log.Printf("Write failed: %v\n", err)
}
}
To launch the server, execute the command: go run. (note the inclusion of the period). Next, open your web browser to visit http://localhost:8080/spinwheel to observe the server in operation.
Step 3: Add Dependencies to Integrate OpenTelemetry Into the Go App
Now that your HTTP server is running, the next step is to integrate OpenTelemetry into your Go application. You need to add several dependencies, including the following:
- OpenTelemetry SDK
- Standard exporters for metrics and traces
- Instrumentation for the net/http package
Run the following command to install these packages:
go get "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"" ""go.opentelemetry.io/otel/exporters/stdout/stdouttrace"" ""go.opentelemetry.io/otel/propagation"" ""go.opentelemetry.io/otel/sdk/metric"" ""go.opentelemetry.io/otel/sdk/resource"" ""go.opentelemetry.io/otel/sdk/trace"" ""go.opentelemetry.io/otel/semconv/v1.24.0"" ""go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp""
Executing the above command ensures that your project has all the essential libraries for instrumenting Golang applications using OpenTelemetry. This setup provides comprehensive support for tracing capabilities by adding the following:
- Core OpenTelemetry library
- OTLP trace exporter
- Resource SDK
- Trace API
Note
If you’re instrumenting an app, use the appropriate OpenTelemetry SDK for your language. You’ll then use the SDK to initialize OpenTelemetry and the API to instrument your code.
Step 4: Initialize the OpenTelemetry SDK
After adding the necessary dependencies, the next step is to configure the OpenTelemetry SDK. This setup is critical for exporting your application’s telemetry data, including traces and metrics. Create a new file named otel.go to bootstrap in the OpenTelemetry pipeline.
In the otel.go file, you will define configurations for trace and metric providers, and establish a propagator. Below is an example of how the code in otel.go should look, outlining the initialization process for the OpenTelemetry SDK:
package main
import (
// ...other imports...
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"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.7.0"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
func main() {
// Initialize OpenTelemetry SDK
ctx := context.Background()
exporter, err := otlptracegrpc.New(ctx)
handleErr(err, "Failed to create exporter")
openTelemetryURL := attribute.KeyValue{
Key: attribute.Key("opentelemetry.io/schemas"),
Value: attribute.StringValue("1.7.0"),
}
resource, err := resource.New(ctx,
resource.WithAttributes(
semconv.SchemaURL,
openTelemetryURL,
),
)
handleErr(err, "Failed to create resource")
tracerProvider := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource),
)
otel.SetTracerProvider(tracerProvider)
otel.SetTextMapPropagator(propagation.TraceContext{})
}
This configuration initiates the OpenTelemetry SDK, sets up the OTLP trace exporter, and establishes the resource attributes. It ensures that your Go application is ready to collect and export telemetry data efficiently.
Step 5: Instrument the HTTP Server
Next, you need to enhance the main function to gather telemetry data from your HTTP server.go file. This step involves the use of otelhttp middleware to track and collect metrics and traces for HTTP requests automatically.
Enhance your main function in the main.go file by setting up the OpenTelemetry SDK and then applying the ‘otelhttp.NewHandler’ to your server’s HTTP handlers. This method wraps your existing HTTP handlers, enabling them to capture detailed telemetry data seamlessly.
Here’s an example of how to modify your code (note that some parts of the code are simplified for clarity):package main
import (
…
"context"
"errors"
"log"
"net"
"net/http"
"os"
"os/signal"
"time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
func main() {
if err := run(); err != nil {
log.Fatalln(err)
}
}
func run() (err error) {
// Handle shutdown scenarios
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
otelShutdown, err := bootstrap_sdk(ctx)
if err != nil {
return
}
defer func() {
err = errors.Join(err, otelShutdown(context.Background()))
}()
// Start HTTP server.
srv := &http.Server{
Addr: ":8080",
BaseContext: func(_ net.Listener) context.Context { return ctx },
ReadTimeout: time.Second,
WriteTimeout: 10 * time.Second,
Handler: newHTTPHandler(),
}
srvErr := make(chan error, 1)
go func() {
srvErr <- srv.ListenAndServe()
}()
// Handle interruptions
select {
case err = <-srvErr:
return
case <-ctx.Done():
stop()
}
err = srv.Shutdown(context.Background())
return
}
func newHTTPHandler() http.Handler {
mux := http.NewServeMux()
handleFunc := func(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) {
handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc))
mux.Handle(pattern, handler)
}
handleFunc("/spinwheel", spinwheel)
// Add HTTP instrumentation for the whole server
handler := otelhttp.NewHandler(mux, "/")
return handler
}
This modification fully instruments your HTTP server to record and export telemetry data, improving performance and usage visibility.
Step 6: Enhance Observability by Adding Custom Instrumentation
For more detailed observability of your application, you can introduce custom instrumentation. This advanced step lets you create traces for specific code operations to monitor and diagnose your application’s behavior more precisely.
Incorporate the following enhancements into your main.go file to implement this capability:package main
import (
// ...other imports...
"go.opentelemetry.io/otel/trace"
)
func main() {
// ...other code...
tracer := otel.GetTracerProvider().Tracer("example")
http.Handle("/", otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, span := tracer.Start(r.Context(), "my-operation")
defer span.End()
fmt.Fprint(w, "Hello, OpenTelemetry!")
}), "/"))
http.ListenAndServe(":8080", nil)
}
This code initiates a new trace span for an operation labeled “my-operation” whenever the root URL is accessed. The span is directly linked to the context of the incoming request, ensuring that all telemetry data remains coherent and accurately represents the operation’s execution.
Since the span automatically closes once the operation completes, it encapsulates the lifecycle of this particular action within your server’s operations.
This customization makes your application more observable and helps identify your server’s performance bottlenecks or workflow issues.
Step 7: Run the Application
Finally, to run your instrumented application, streamline your module dependencies using the command go mod tidy
. Next, configure the OTEL_RESOURCE_ATTRIBUTES environment variable to assign resource attributes, such as the service name and version.
Launch your application once your setup is complete by entering ‘go run main.go’ in the terminal.
To generate traces, navigate to http://<your IP address>:8080 in your web browser. The traces generated can be accessed and reviewed through your OpenTelemetry collector or your chosen observability platform.
Conclusion
Instrumenting Golang applications using OpenTelemetry is an effective way to trace requests, measure metrics, and log important events. With OpenTelemetry, developers can more deeply optimize their telemetry workflows, helping them complete picture of the application to streamline debugging and performance optimization.
FAQs on How to Instrument Golang Applications Using OpenTelementry
How to instrument an app with OpenTelemetry?
To instrument an app, install the OpenTelemetry SDK for your language. Then, initialize OpenTelemetry with the SDK and instrument your code using the API. It will send telemetry from your app and any libraries you install that include instrumentation.
How to use OpenTelemetry in Go?
To use OpenTelemetry in Go, import the OpenTelemetry Go SDK and initialize the tracer. Instrument your code by creating spans and recording metrics. Export the collected telemetry data to your chosen backend.
What is OpenTelemetry auto instrumentation?
OpenTelemetry auto instrumentation dynamically injects code at runtime to capture and send telemetry data, without requiring you to modify your application code. It typically measures CPU, memory, request latency and error rates. Though it’s less flexible than manual instrumentation, implementation via auto-instrumentation is easier and faster.