> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenTelemetry Go Installation

Please follow the [installation guide](/guides/new-application) first, when adding a new application to AppSignal.

Then make sure to [install the AppSignal collector](/collector/installation) before proceeding.

## Configure OpenTelemetry in your application

OpenTelemetry must be initialized before your application starts, to ensure that all telemetry data is sent through the exporter to AppSignal. For example, in a web application, OpenTelemetry must be initialized before the routes are loaded and the server starts.

Create an `initOpenTelemetry()` function like the one in the example below and add it to your application's main file.

Make sure to update the values below with your AppSignal application name, environment and push API key, and to replace the exporter endpoint with the address of your AppSignal collector if needed.

<CodeGroup>
  ```go Go theme={null}
  package main

  import (
  	// Import these standard libraries used in the OpenTelemetry configuration
  	"context"
  	"log"
  	"os"
  	"os/exec"
  	"strings"

  	// Import these OpenTelemetry libraries
  	"go.opentelemetry.io/otel"
  	"go.opentelemetry.io/otel/attribute"
  	"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
  	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
  	"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
  	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
  	"go.opentelemetry.io/otel/log/global"
  	"go.opentelemetry.io/otel/propagation"
  	sdklog "go.opentelemetry.io/otel/sdk/log"
  	sdkmetric "go.opentelemetry.io/otel/sdk/metric"
  	sdkresource "go.opentelemetry.io/otel/sdk/resource"
  	sdktrace "go.opentelemetry.io/otel/sdk/trace"
  )

  func initOpenTelemetry() func() {
  	// Replace these values with your AppSignal application name, environment
  	// and push API key. These are used by the resource attributes configuration below.
  	name := "My app"
  	push_api_key := "0000-0000-0000-0000"
  	environment := "development"

  	// Set the name of the service that is being monitored. A common choice is the
  	// name of the framework used. This is used to group traces and metrics in AppSignal.
  	service_name := "My service name"

  	// Replace `localhost:8099` with the address of your AppSignal collector
  	// if it's running on another host.
  	endpoint := "localhost:8099"

  	hostname, err := os.Hostname()
  	if err != nil {
  		hostname = "unknown"
  	}

  	var revision string
  	cmd := exec.Command("git", "rev-parse", "--short", "HEAD")
  	output, err := cmd.Output()
  	if err != nil {
  		revision = "unknown"
  	} else {
  		revision = strings.TrimSpace(string(output))
  	}

  	resource, err := sdkresource.Merge(
  		sdkresource.Default(),
  		sdkresource.NewSchemaless(
  			attribute.String("appsignal.config.name", name),
  			attribute.String("appsignal.config.environment", environment),
  			attribute.String("appsignal.config.push_api_key", push_api_key),
  			attribute.String("appsignal.config.revision", revision),
  			attribute.String("appsignal.config.language_integration", "go"),
  			attribute.String("appsignal.config.app_path", os.Getenv("PWD")),
  			attribute.String("service.name", service_name),
  			attribute.String("host.name", hostname),
  		),
  	)
  	if err != nil {
  		log.Fatalf("Error creating OTLP resource: %v", err)
  	}

  	// Tracing
  	traceClient := otlptracehttp.NewClient(
  		otlptracehttp.WithInsecure(), // Remove if the collector is accessible via HTTPS
  		otlptracehttp.WithEndpoint(endpoint),
  	)

  	traceExporter, err := otlptrace.New(context.Background(), traceClient)
  	if err != nil {
  		log.Fatalf("Error creating OTLP trace exporter: %v", err)
  	}

  	tracerProvider := sdktrace.NewTracerProvider(
  		sdktrace.WithBatcher(traceExporter),
  		sdktrace.WithResource(resource),
  	)

  	otel.SetTracerProvider(tracerProvider)
  	otel.SetTextMapPropagator(
  		propagation.NewCompositeTextMapPropagator(
  			propagation.TraceContext{},
  			propagation.Baggage{},
  		),
  	)

  	// Metrics
  	metricExporter, err := otlpmetrichttp.New(
  		context.Background(),
  		otlpmetrichttp.WithInsecure(), // Remove if the collector is accessible via HTTPS
  		otlpmetrichttp.WithEndpoint(endpoint),
  	)
  	if err != nil {
  		log.Fatalf("creating OTLP metric exporter: %v", err)
  	}

  	meterProvider := sdkmetric.NewMeterProvider(
  		sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExporter)),
  		sdkmetric.WithResource(resource),
  	)
  	otel.SetMeterProvider(meterProvider)

  	// Logs
  	logExporter, err := otlploghttp.New(
  		context.Background(),
  		otlploghttp.WithInsecure(), // Remove if the collector is accessible via HTTPS
  		otlploghttp.WithEndpoint(endpoint),
  	)
  	if err != nil {
  		log.Fatalf("creating OTLP log exporter: %v", err)
  	}

  	loggerProvider := sdklog.NewLoggerProvider(
  		sdklog.WithResource(resource),
  		sdklog.WithProcessor(
  			sdklog.NewBatchProcessor(logExporter),
  		),
  	)
  	global.SetLoggerProvider(loggerProvider)

  	// Cleanup
  	return func() {
  		ctx := context.Background()
  		if err := tracerProvider.Shutdown(ctx); err != nil {
  			log.Println("Error shutting down tracer provider:", err)
  		}
  		if err := meterProvider.Shutdown(ctx); err != nil {
  			log.Println("Error shutting down meter provider:", err)
  		}
  		if err := loggerProvider.Shutdown(ctx); err != nil {
  			log.Println("Error shutting down logger provider:", err)
  		}
  	}
  }

  func main() {
  	cleanup := initOpenTelemetry()
  	defer cleanup()

  	// ... your application's initialization code
  }
  ```
</CodeGroup>

*If your collector is accessible through HTTPS, remove the three lines that contain the `WithInsecure()` method call in the example config.*

To install the OpenTelemetry libraries imported in the example above, run this command.

<CodeGroup>
  ```sh Shell theme={null}
  go mod tidy
  ```
</CodeGroup>

## Configure OpenTelemetry instrumentation packages

The OpenTelemetry stack will not emit any data by itself. To instrument your application, install and configure the instrumentation packages for the libraries and frameworks used by your application. You can [find OpenTelemetry instrumentation packages at the OpenTelemetry registry](https://opentelemetry.io/ecosystem/registry/?s=\&component=instrumentation\&language=go\&flag=all).

For some popular OpenTelemetry instrumentations, you can find specific configuration instructions in these pages:

* [Gin-gonic](/go/instrumentations/gin-gonic)
* [Gorilla mux](/go/instrumentations/gorilla-mux)
* [MongoDB](/go/instrumentations/mongo)
* [Redis](/go/instrumentations/redis)
* [SQL](/go/instrumentations/sql)

## Test the app!

Now that all the components are connected, start your app and test if you see data arrive in AppSignal. Check the ["Errors > Issue list"](https://appsignal.com/redirect-to/app?to=exceptions) and ["Performance > Traces"](https://appsignal.com/redirect-to/app?to=performance/traces) page specifically.

If after following our installation instructions you still don't see data in AppSignal, [let us know](mailto:support@appsignal.com?subject=OpenTelemetry%20beta%20issue) and we'll help you finalize your OpenTelemetry installation!

## Add Instrumentation Packages

The next step is to instrument Go packages like Gin-gonic, Gorilla, etc. This will provide much more data to really dig into the performance of your applications.

The steps for every package are usually as follows:

* Install the OpenTelemetry instrumentation package for the library you want to instrument.
* Follow the installation instructions for the instrumentation package.

For more installation and configuration information per library, please consult the [Go instrumentations section][instrumentations].

[Go language]: https://go.dev/

[OpenTelemetry]: https://opentelemetry.io/

[instrumentations]: /go/instrumentations.html
