This document contains instructions on how to set up OpenTelemetry instrumentation in your Go applications and view your application traces in SigNoz.
Send Traces to SigNoz Cloud
From VMs, there are two ways to send data to SigNoz Cloud.
Send traces directly to SigNoz Cloud
Install Dependencies
Dependencies related to OpenTelemetry exporter and SDK have to be installed first. Note that we are assuming you are usingginrequest router. If you are using other request routers, check out the corresponding package.Run the below commands after navigating to the application source folder:
go get go.opentelemetry.io/otel \ go.opentelemetry.io/otel/trace \ go.opentelemetry.io/otel/sdk \ go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin \ go.opentelemetry.io/otel/exporters/otlp/otlptrace \ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpcDeclare environment variables for configuring OpenTelemetry
Declare the following global variables inmain.gowhich we will use to configure OpenTelemetry:var ( serviceName = os.Getenv("SERVICE_NAME") collectorURL = os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") insecure = os.Getenv("INSECURE_MODE") )Instrument your Go application with OpenTelemetry
To configure your application to send data we will need a function to initialize OpenTelemetry. Add the following snippet of code in yourmain.gofile.import ( ..... "google.golang.org/grpc/credentials" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func initTracer() func(context.Context) error { var secureOption otlptracegrpc.Option if strings.ToLower(insecure) == "false" || insecure == "0" || strings.ToLower(insecure) == "f" { secureOption = otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) } else { secureOption = otlptracegrpc.WithInsecure() } exporter, err := otlptrace.New( context.Background(), otlptracegrpc.NewClient( secureOption, otlptracegrpc.WithEndpoint(collectorURL), ), ) if err != nil { log.Fatalf("Failed to create exporter: %v", err) } resources, err := resource.New( context.Background(), resource.WithAttributes( attribute.String("service.name", serviceName), attribute.String("library.language", "go"), ), ) if err != nil { log.Fatalf("Could not set resources: %v", err) } otel.SetTracerProvider( sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resources), ), ) return exporter.Shutdown }Initialize the tracer in main.go
Modify the main function to initialise the tracer inmain.go. Initiate the tracer at the very beginning of our main function.func main() { cleanup := initTracer() defer cleanup(context.Background()) ...... }Add the OpenTelemetry Gin middleware
Configure Gin to use the middleware by adding the following lines inmain.go.import ( .... "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) func main() { ...... r := gin.Default() r.Use(otelgin.Middleware(serviceName)) ...... }Set environment variables and run your Go Gin application
The run command must have some environment variables to send data to SigNoz cloud. The run command:SERVICE_NAME=<service_name> INSECURE_MODE=false OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=<your-ingestion-key> OTEL_EXPORTER_OTLP_ENDPOINT=ingest.<region>.signoz.cloud:443 go run main.go- Set the
<region>to match your SigNoz Cloud region - Replace
<your-ingestion-key>with your SigNoz ingestion key <service_name>is name of your service
- Set the
Send traces via OTel Collector binary
- Install OTel Collector binary
OTel Collector binary helps to collect logs, hostmetrics, resource and infra attributes.
You can find instructions to install OTel Collector binary here in your VM.
Install Dependencies
Dependencies related to OpenTelemetry exporter and SDK have to be installed first. Note that we are assuming you are usingginrequest router. If you are using other request routers, check out the corresponding package.Run the below commands after navigating to the application source folder:
go get go.opentelemetry.io/otel \ go.opentelemetry.io/otel/trace \ go.opentelemetry.io/otel/sdk \ go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin \ go.opentelemetry.io/otel/exporters/otlp/otlptrace \ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpcDeclare environment variables for configuring OpenTelemetry
Declare the following global variables inmain.gowhich we will use to configure OpenTelemetry:var ( serviceName = os.Getenv("SERVICE_NAME") collectorURL = os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") insecure = os.Getenv("INSECURE_MODE") )Instrument your Go application with OpenTelemetry
To configure your application to send data we will need a function to initialize OpenTelemetry. Add the following snippet of code in yourmain.gofile.import ( ..... "google.golang.org/grpc/credentials" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func initTracer() func(context.Context) error { var secureOption otlptracegrpc.Option if strings.ToLower(insecure) == "false" || insecure == "0" || strings.ToLower(insecure) == "f" { secureOption = otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) } else { secureOption = otlptracegrpc.WithInsecure() } exporter, err := otlptrace.New( context.Background(), otlptracegrpc.NewClient( secureOption, otlptracegrpc.WithEndpoint(collectorURL), ), ) if err != nil { log.Fatalf("Failed to create exporter: %v", err) } resources, err := resource.New( context.Background(), resource.WithAttributes( attribute.String("service.name", serviceName), attribute.String("library.language", "go"), ), ) if err != nil { log.Fatalf("Could not set resources: %v", err) } otel.SetTracerProvider( sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resources), ), ) return exporter.Shutdown }Initialize the tracer in main.go
Modify the main function to initialise the tracer inmain.go. Initiate the tracer at the very beginning of our main function.func main() { cleanup := initTracer() defer cleanup(context.Background()) ...... }Add the OpenTelemetry Gin middleware
Configure Gin to use the middleware by adding the following lines inmain.go.import ( .... "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) func main() { ...... r := gin.Default() r.Use(otelgin.Middleware(serviceName)) ...... }Set environment variables and run your Go Gin application
The run command must have some environment variables to send data to SigNoz. The run command:SERVICE_NAME=<service_name> INSECURE_MODE=true OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 go run main.go<service_name>is name of your serviceYou can validate if your application is sending traces to SigNoz cloud by following the instructions here.
You can auto-instrument sending traces from the Golang application using one of the following methods:
- Using OTel Collector Agent
- Using Kubernetes OTel Operator
For Golang application deployed on Kubernetes, you need to install OTel Collector agent in your k8s infra to collect and send traces to SigNoz Cloud. You can find the instructions to install OTel Collector agent here.
Once you have set up OTel Collector agent, you can proceed with OpenTelemetry Golang instrumentation by following the below steps:
Install Dependencies
Dependencies related to OpenTelemetry exporter and SDK have to be installed first. Note that we are assuming you are usingginrequest router. If you are using other request routers, check out the corresponding package.Run the below commands after navigating to the application source folder:
go get go.opentelemetry.io/otel \ go.opentelemetry.io/otel/trace \ go.opentelemetry.io/otel/sdk \ go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin \ go.opentelemetry.io/otel/exporters/otlp/otlptrace \ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpcDeclare environment variables for configuring OpenTelemetry
Declare the following global variables inmain.gowhich we will use to configure OpenTelemetry:var ( serviceName = os.Getenv("SERVICE_NAME") collectorURL = os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") insecure = os.Getenv("INSECURE_MODE") )Instrument your Go application with OpenTelemetry
To configure your application to send data we will need a function to initialize OpenTelemetry. Add the following snippet of code in yourmain.gofile.import ( ..... "google.golang.org/grpc/credentials" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func initTracer() func(context.Context) error { var secureOption otlptracegrpc.Option if strings.ToLower(insecure) == "false" || insecure == "0" || strings.ToLower(insecure) == "f" { secureOption = otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) } else { secureOption = otlptracegrpc.WithInsecure() } exporter, err := otlptrace.New( context.Background(), otlptracegrpc.NewClient( secureOption, otlptracegrpc.WithEndpoint(collectorURL), ), ) if err != nil { log.Fatalf("Failed to create exporter: %v", err) } resources, err := resource.New( context.Background(), resource.WithAttributes( attribute.String("service.name", serviceName), attribute.String("library.language", "go"), ), ) if err != nil { log.Fatalf("Could not set resources: %v", err) } otel.SetTracerProvider( sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resources), ), ) return exporter.Shutdown }Initialize the tracer in main.go
Modify the main function to initialise the tracer inmain.go. Initiate the tracer at the very beginning of our main function.func main() { cleanup := initTracer() defer cleanup(context.Background()) ...... }Add the OpenTelemetry Gin middleware
Configure Gin to use the middleware by adding the following lines inmain.go.import ( .... "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) func main() { ...... r := gin.Default() r.Use(otelgin.Middleware(serviceName)) ...... }Set environment variables and run your Go Gin application
The run command must have some environment variables to send data to SigNoz. The run command:SERVICE_NAME=<service_name> INSECURE_MODE=true OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 go run main.go<service_name>is name of your serviceYou can validate if your application is sending traces to SigNoz cloud by following the instructions here.
K8s OTel Operator Based Automatic Instrumentation
Send traces directly to SigNoz Cloud - Using K8s OTel Operator
For Golang application deployed on Kubernetes, you can auto-instrument the traces using Kubernetes OpenTelemetry Operator.
The OTel Operator for Golang is not yet production ready. You can check the latest status of the Otel Operator for Golang here. We recommend to use this in production only after it is marked as ready for production use.
An OpenTelemetry Operator is a Kubernetes Operator that manages OpenTelemetry Collectors and auto-instrumentation of workloads. It basically simplifies the deployment and management of OpenTelemetry in a Kubernetes environment.
The OpenTelemetry Operator provides two Custom Resource Definitions (CRDs):
OpenTelemetryCollectorInstrumentation
The OpenTelemetryCollector CRD allows you to deploy and manage OpenTelemetry Collectors in your Kubernetes cluster.
The Instrumentation CRD allows you to configure and inject OpenTelemetry auto-instrumentation libraries into your workloads.
Here are the steps you need to follow to auto-instrument Golang application using OTel Operator:
Step 1. Install cert-manager
Run the following commands to apply cert manager.
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.1/cert-manager.yaml
kubectl wait --for=condition=Available deployments/cert-manager -n cert-manager
Step 2. Install OpenTelemetry Operator
To install the operator in the existing K8s cluster, run the following command:
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/download/v0.116.0/opentelemetry-operator.yaml
Installing the OpenTelemetry Operator sets up the necessary components and configurations to enable the observability and monitoring of applications running in the cluster.
Step 3. Setup the OpenTelemetry Collector instance
Once the opentelemetry-operator has been deployed, you can proceed with the creation of the OpenTelemetry Collector (otelcol) instance. The OpenTelemetry Collector collects, processes, and exports telemetry data.
There are different deployment modes for the OpenTelemetryCollector, and you can specify them in the spec.mode section of the custom resource. The available deployment modes are:
- Daemonset
- Sidecar
- StatefulSet
- Deployment (default mode)
The default method - the Deployment mode, will be used here.
To create a simple instance of the OpenTelemetry Collector, create a file otel-collector.yaml with the following contents:
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel-collector
spec:
mode: deployment
config: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch: {}
resource/env:
attributes:
- key: deployment.environment
value: prod # can be dev, prod, staging etc. based on your environment
action: upsert
exporters:
debug: {}
otlp:
endpoint: "ingest.<region>.signoz.cloud:443" # replace <region> with your region of SigNoz Cloud
tls:
insecure: false
headers:
"signoz-ingestion-key": "<your-ingestion-key>" # Obtain from https://{your-signoz-tenant-url}/settings/ingestion-settings
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, resource/env]
exporters: [otlp]
- Set the
<region>to match your SigNoz Cloud region - Replace
<your-ingestion-key>with your SigNoz ingestion key
Apply the above yaml file using the following command:
kubectl apply -f otel-collector.yaml
Step 4. Setup the Instrumentation instance
Once the OpenTelemetry Collector instance has been deployed, the next step will be to create an instrumentation instance, which will be responsible for sending OTLP data to the OTel Collector.
Create a file instrumentation.yaml with the following contents:
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: traces-instrumentation
spec:
exporter:
endpoint: https://ingest.<region>.signoz.cloud:443 # replace <region> with your region of SigNoz Cloud
env:
- name: OTEL_EXPORTER_OTLP_HEADERS
value: signoz-ingestion-key="<signoz-token>" # Obtain from https://{your-signoz-url}/settings/ingestion-settings
- name: OTEL_EXPORTER_OTLP_INSECURE
value: "false"
propagators:
- tracecontext
- baggage
- b3
sampler:
type: parentbased_traceidratio
argument: "1"
go:
image: ghcr.io/open-telemetry/opentelemetry-go-instrumentation/autoinstrumentation-go:latest
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://otel-collector-collector:4318 #This is formed as: "http://<OpenTelemetryCollector name>-collector:4318"
Apply the above instrumentation using the following command:
kubectl apply -f instrumentation.yaml
Step 5. Auto-instrument your .NET app with OpenTelemetry
Create deployment.yaml file for your .NET application as follows:
apiVersion: apps/v1
kind: Deployment
metadata:
name: golang-app
spec:
selector:
matchLabels:
app: golang-app
replicas: 1
template:
metadata:
labels:
app: golang-app
annotations:
instrumentation.opentelemetry.io/inject-go: "true"
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/app/server"
resource.opentelemetry.io/service.name: "golang-app"
spec:
containers:
- name: app
image: golang-app:latest
ports:
- containerPort: 8080
- name: autoinstrumentation-go
image: otel/autoinstrumentation-go
imagePullPolicy: IfNotPresent
env:
- name: OTEL_GO_AUTO_TARGET_EXE
value: "/app/server"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector-collector:4318" #This is formed as: "http://<OpenTelemetryCollector name>-collector:4318"
- name: OTEL_SERVICE_NAME
value: "golang-app"
securityContext:
runAsUser: 0
privileged: true
dnsPolicy: ClusterFirst
restartPolicy: Always
shareProcessNamespace: true
It is important to add the following annotation under spec > template > metadata > annotations:
instrumentation.opentelemetry.io/inject-go: "true"
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/app/server" # This is the location of target application binary
This helps in auto-instrumenting the traces from the Golang application.
Note that for Golang, we need to add a specific container for auto-instrumentation: autoinstrumentation-go. All the OTel related environment variables have been provided as part of this container.
Apply the deployment using the following command:
kubectl apply -f deployment.yaml
With this, the auto-instrumentation of traces for Golang application is ready.
Step 6. Running the Golang application
In order to run the application on port 8080, run the following commands:
export POD_NAME=$(kubectl get pod -l app=<service-name> -o jsonpath="{.items[0].metadata.name}") # service name is `golang-app` in this case.
kubectl port-forward ${POD_NAME} 8080:8080
You can now access the application on port 8080.
You can validate if your application is sending traces to SigNoz cloud here.
In case you encounter an issue where all applications do not get listed in the services section then please refer to the troubleshooting section.
From Windows, there are two ways to send data to SigNoz Cloud.
- Send traces directly to SigNoz Cloud
- Send traces via OTel Collector binary (recommended)
Send traces directly to SigNoz Cloud
Install Dependencies
Dependencies related to OpenTelemetry exporter and SDK have to be installed first. Note that we are assuming you are usingginrequest router. If you are using other request routers, check out the corresponding package.Run the below commands after navigating to the application source folder:
go get go.opentelemetry.io/otel \ go.opentelemetry.io/otel/trace \ go.opentelemetry.io/otel/sdk \ go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin \ go.opentelemetry.io/otel/exporters/otlp/otlptrace \ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpcDeclare environment variables for configuring OpenTelemetry
Declare the following global variables inmain.gowhich we will use to configure OpenTelemetry:var ( serviceName = os.Getenv("SERVICE_NAME") collectorURL = os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") insecure = os.Getenv("INSECURE_MODE") )Instrument your Go application with OpenTelemetry
To configure your application to send data we will need a function to initialize OpenTelemetry. Add the following snippet of code in yourmain.gofile.import ( ..... "google.golang.org/grpc/credentials" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func initTracer() func(context.Context) error { var secureOption otlptracegrpc.Option if strings.ToLower(insecure) == "false" || insecure == "0" || strings.ToLower(insecure) == "f" { secureOption = otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) } else { secureOption = otlptracegrpc.WithInsecure() } exporter, err := otlptrace.New( context.Background(), otlptracegrpc.NewClient( secureOption, otlptracegrpc.WithEndpoint(collectorURL), ), ) if err != nil { log.Fatalf("Failed to create exporter: %v", err) } resources, err := resource.New( context.Background(), resource.WithAttributes( attribute.String("service.name", serviceName), attribute.String("library.language", "go"), ), ) if err != nil { log.Fatalf("Could not set resources: %v", err) } otel.SetTracerProvider( sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resources), ), ) return exporter.Shutdown }Initialize the tracer in main.go
Modify the main function to initialise the tracer inmain.go. Initiate the tracer at the very beginning of our main function.func main() { cleanup := initTracer() defer cleanup(context.Background()) ...... }Add the OpenTelemetry Gin middleware
Configure Gin to use the middleware by adding the following lines inmain.go.import ( .... "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) func main() { ...... r := gin.Default() r.Use(otelgin.Middleware(serviceName)) ...... }Set environment variables and run your Go Gin application
The run command must have some environment variables to send data to SigNoz cloud. The run commands:set SERVICE_NAME=<service_name> set INSECURE_MODE=false set OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=<your-ingestion-key> set OTEL_EXPORTER_OTLP_ENDPOINT=ingest.<region>.signoz.cloud:443go run main.go- Set the
<region>to match your SigNoz Cloud region - Replace
<your-ingestion-key>with your SigNoz ingestion key <service_name>is name of your service
- Set the
Send traces via OTel Collector binary
- Install OTel Collector binary
OTel Collector binary helps to collect logs, hostmetrics, resource and infra attributes.
You can find instructions to install OTel Collector binary here in your VM.
Install Dependencies
Dependencies related to OpenTelemetry exporter and SDK have to be installed first. Note that we are assuming you are usingginrequest router. If you are using other request routers, check out the corresponding package.Run the below commands after navigating to the application source folder:
go get go.opentelemetry.io/otel \ go.opentelemetry.io/otel/trace \ go.opentelemetry.io/otel/sdk \ go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin \ go.opentelemetry.io/otel/exporters/otlp/otlptrace \ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpcDeclare environment variables for configuring OpenTelemetry
Declare the following global variables inmain.gowhich we will use to configure OpenTelemetry:var ( serviceName = os.Getenv("SERVICE_NAME") collectorURL = os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") insecure = os.Getenv("INSECURE_MODE") )Instrument your Go application with OpenTelemetry
To configure your application to send data we will need a function to initialize OpenTelemetry. Add the following snippet of code in yourmain.gofile.import ( ..... "google.golang.org/grpc/credentials" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func initTracer() func(context.Context) error { var secureOption otlptracegrpc.Option if strings.ToLower(insecure) == "false" || insecure == "0" || strings.ToLower(insecure) == "f" { secureOption = otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) } else { secureOption = otlptracegrpc.WithInsecure() } exporter, err := otlptrace.New( context.Background(), otlptracegrpc.NewClient( secureOption, otlptracegrpc.WithEndpoint(collectorURL), ), ) if err != nil { log.Fatalf("Failed to create exporter: %v", err) } resources, err := resource.New( context.Background(), resource.WithAttributes( attribute.String("service.name", serviceName), attribute.String("library.language", "go"), ), ) if err != nil { log.Fatalf("Could not set resources: %v", err) } otel.SetTracerProvider( sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resources), ), ) return exporter.Shutdown }Initialize the tracer in main.go
Modify the main function to initialise the tracer inmain.go. Initiate the tracer at the very beginning of our main function.func main() { cleanup := initTracer() defer cleanup(context.Background()) ...... }Add the OpenTelemetry Gin middleware
Configure Gin to use the middleware by adding the following lines inmain.go.import ( .... "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) func main() { ...... r := gin.Default() r.Use(otelgin.Middleware(serviceName)) ...... }Set environment variables and run your Go Gin application
The run command must have some environment variables to send data to SigNoz. Then run the following commands:set SERVICE_NAME=<service_name> set INSECURE_MODE=true set OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317go run main.go<service_name>is name of your serviceYou can validate if your application is sending traces to SigNoz cloud by following the instructions here.
Send Traces to Self-Hosted SigNoz
Install Dependencies
Dependencies related to OpenTelemetry exporter and SDK have to be installed first. Note that we are assuming you are usingginrequest router. If you are using other request routers, check out the corresponding package.Run the below commands after navigating to the application source folder:
go get go.opentelemetry.io/otel \ go.opentelemetry.io/otel/trace \ go.opentelemetry.io/otel/sdk \ go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin \ go.opentelemetry.io/otel/exporters/otlp/otlptrace \ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpcDeclare environment variables for configuring OpenTelemetry
Declare the following global variables inmain.gowhich we will use to configure OpenTelemetry:var ( serviceName = os.Getenv("SERVICE_NAME") collectorURL = os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") insecure = os.Getenv("INSECURE_MODE") )Instrument your Go application with OpenTelemetry
To configure your application to send data we will need a function to initialize OpenTelemetry. Add the following snippet of code in yourmain.gofile.import ( ..... "google.golang.org/grpc/credentials" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func initTracer() func(context.Context) error { var secureOption otlptracegrpc.Option if strings.ToLower(insecure) == "false" || insecure == "0" || strings.ToLower(insecure) == "f" { secureOption = otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) } else { secureOption = otlptracegrpc.WithInsecure() } exporter, err := otlptrace.New( context.Background(), otlptracegrpc.NewClient( secureOption, otlptracegrpc.WithEndpoint(collectorURL), ), ) if err != nil { log.Fatalf("Failed to create exporter: %v", err) } resources, err := resource.New( context.Background(), resource.WithAttributes( attribute.String("service.name", serviceName), attribute.String("library.language", "go"), ), ) if err != nil { log.Fatalf("Could not set resources: %v", err) } otel.SetTracerProvider( sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resources), ), ) return exporter.Shutdown }Initialize the tracer in main.go
Modify the main function to initialise the tracer inmain.go. Initiate the tracer at the very beginning of our main function.func main() { cleanup := initTracer() defer cleanup(context.Background()) ...... }Add the OpenTelemetry Gin middleware
Configure Gin to use the middleware by adding the following lines inmain.go.import ( .... "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) func main() { ...... r := gin.Default() r.Use(otelgin.Middleware(serviceName)) ...... }Set environment variables and run your Go Gin application
The run command must have some environment variables to send data to SigNoz. The run command:SERVICE_NAME=<service_name> INSECURE_MODE=true OTEL_EXPORTER_OTLP_ENDPOINT=<IP of SigNoz backend:4317> go run main.go<service_name>is name of your serviceOTEL_EXPORTER_OTLP_ENDPOINT: localhost:4317Since, we have installed SigNoz on our local machine, we use the above IP. If you install SigNoz on a different machine, you can update it with the relevant IP.
Do not use
httporhttpsin the IP address. For example, if the IP ishttp://test.comthen theOTEL_EXPORTER_OTLP_ENDPOINTwill betest.com:4317.Here’s a handy grid to figure out which address to use to send data to SigNoz.
Hence, the final run command looks like this:
SERVICE_NAME=<service_name> INSECURE_MODE=true OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 go run main.go<service_name>is name of your service
Validating instrumentation by checking for traces
With your application running, you can verify that you’ve instrumented your application with OpenTelemetry correctly by confirming that tracing data is being reported to SigNoz.
To do this, you need to ensure that your application generates some data. Applications will not produce traces unless they are being interacted with, and OpenTelemetry will often buffer data before sending. So you need to interact with your application and wait for some time to see your tracing data in SigNoz.
Validate your traces in SigNoz:
- Trigger an action in your app that generates a web request. Hit the endpoint a number of times to generate some data. Then, wait for some time.
- In SigNoz, open the
Servicestab. Hit theRefreshbutton on the top right corner, and your application should appear in the list ofApplications. - Go to the
Tracestab, and apply relevant filters to see your application’s traces.
Request Routers
OpenTelemetry gin/gonic instrumentation
# Add one line to your import() stanza depending upon your request router:
middleware "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
and then inject OpenTelemetry middleware:
router.Use(middleware.Middleware(serviceName))
OpenTelemetry gorillamux instrumentation
# Add one line to your import() stanza depending upon your request router:
middleware "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"
and then inject OpenTelemetry middleware:
router.Use(middleware.Middleware(serviceName))
OpenTelemetry echo instrumentation
# Add one line to your import() stanza depending upon your request router:
middleware "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
and then inject OpenTelemetry middleware:
router.Use(middleware.Middleware(serviceName))
If you don’t use a request router
import (
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
In each place where you pass an http.Handler to a ServeMux, you’ll wrap the handler function. For instance, you’ll make the following replacements:
- mux.Handle("/path", h)
+ mux.Handle("/path", otelhttp.NewHandler(h, "description of path"))
- mux.Handle("/path", http.HandlerFunc(f))
+ mux.Handle("/path", otelhttp.NewHandler(http.HandlerFunc(f), "description of path"))
In this fashion, you can ensure that every function you wrap with othttp will automatically have its metadata collected and a corresponding trace started.
Adding custom attributes and custom events to spans
It’s also possible to set custom attributes or tags to a span. To add custom attributes and events follow the below steps:
Import trace and attribute libraries
import ( ... "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" )Fetch current span from context
span := trace.SpanFromContext(c.Request.Context())Set attribute on current
span.SetAttributes(attribute.String("controller", "books"))
We can also set custom events on the span with its own attribute.
span.AddEvent("This is a sample event", trace.WithAttributes(attribute.Int("pid", 4328), attribute.String("sampleAttribute", "Test")))
gRPC Instrumentation with OpenTelemetry
OpenTelemetry can also help you automatically instrument gRPC requests. To instrument any gRPC servers you have.
import (
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
)
func main() {
[...]
// add StatsHandler to gRPC server initialization
s := grpc.NewServer(grpc.StatsHandler(otelgrpc.NewServerHandler()))
}
Similarly, instrument your gRPC client as well by adding otelgrpc when initializing gRPC client
import (
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
)
func main() {
[...]
// add StatsHandler to gRPC client initialization
cc, err := grpc.NewClient(serverUrl, grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
)
}
We have a blog Monitor gRPC calls with OpenTelemetry - explained with a Golang example, do refer to that in case you need a helping hand to work with gRPC server.
Recording Errors and Exceptions
import "go.opentelemetry.io/otel/codes"
// Get the current span from the tracer
span := trace.SpanFromContext(ctx)
// RecordError converts an error into a span event.
span.RecordError(err)
// Mark span as failed.
span.SetStatus(codes.Error, "internal error")
Sample Golang application
We have included a sample gin/gonic application with README.md at https://github.com/SigNoz/sample-golang-app.
Feel free to use this repo to test out OpenTelemetry instrumentation and how to send telemetry data to SigNoz.
Library and framework support
Besides OpenTelemetry core modules, it is important to install instrumentation packages for every important library and framework which your service depends upon. Beyond the critical telemetry data these components emit, library and framework integrations are often required to ensure that the trace context is properly propagated.
OpenTelemetry automatically provides instrumentation for a large number of libraries and frameworks, right out of the box.
The full list of supported instrumentation can be found in the README.
You can also find libraries, plugins, integrations, and other useful tools for extending OpenTelemetry from the OpenTelemetry registry.