Library/Framework | Version |
database/sql | go1.12 to go1.23.0 |
github.com/segmentio/kafka-go | v0.4.1 to v0.4.47 |
google.golang.org/grpc | v1.14.0 to v1.66.0 |
net/http | go1.12 to go1.22.6 |
net/http
, such as Gin, are supported.chmod +x otel-go-instrumentation
sudo OTEL_GO_AUTO_TARGET_EXE=</path/to/executable_binary> \OTEL_SERVICE_NAME=<serviceName> \OTEL_EXPORTER_OTLP_PROTOCOL=grpc \OTEL_TRACES_EXPORTER=otlp \OTEL_EXPORTER_OTLP_ENDPOINT=<endpoint> \OTEL_RESOURCE_ATTRIBUTES=token=<token>,host.name=<hostName> \./otel-go-instrumentation
</path/to/executable_binary>
: The path of the application executable file. It must be an absolute path here.<serviceName>
: The application name. Multiple application processes that use the same serviceName to access will appear as multiple instances under the same application in Application Performance Management (APM). The application name can contain up to 63 characters consisting of lowercase letters, digits, and the hyphen (-) only. It must start with a lowercase letter and end with a digit or lowercase letter.<endpoint>
: The access point obtained in the previous step. Note that you must add the http://
prefix here.<token>
: The business system token obtained in the previous step.<hostName>
: The hostname of this instance, which is the unique identifier of the application instance. It can usually be set to the IP address of the application instance.myService
as the application name, /root
as the execution path, myToken
as the business system token, 192.168.0.10
as the hostname, and http://ap-guangzhou.apm.tencentcs.com:4317
as the access point. The complete startup command is:sudo OTEL_GO_AUTO_TARGET_EXE=/root/myService \OTEL_SERVICE_NAME=myService \OTEL_EXPORTER_OTLP_PROTOCOL=grpc \OTEL_TRACES_EXPORTER=otlp \OTEL_EXPORTER_OTLP_ENDPOINT=http://ap-guangzhou.apm.tencentcs.com:4317 \OTEL_RESOURCE_ATTRIBUTES=token=myToken,host.name=192.168
.0.10
\./otel-go-instrumentation
instrumentation loaded successfully
field, indicating successful access.{"level":"info","ts":1725609047.2234442,"logger":"go.opentelemetry.io/auto","caller":"cli/main.go:119","msg":"starting instrumentation..."}{"level":"info","ts":1725609047.2235398,"logger":"Instrumentation.Manager","caller":"instrumentation/manager.go:195","msg":"loading probe","name":"net/http/server"}{"level":"info","ts":1725609047.388379,"logger":"go.opentelemetry.io/auto","caller":"cli/main.go:115","msg":"instrumentation loaded successfully"}
{"level":"info","ts":1725609014.2038825,"logger":"go.opentelemetry.io/auto","caller":"cli/main.go:86","msg":"building OpenTelemetry Go instrumentation ...","globalImpl":false}
OTEL_GO_AUTO_TARGET_EXE
) is incorrect.traces export: failed to exit idle mode: dns resolver: missing address
http://
prefix added.import (..."go.opentelemetry.io/otel""go.opentelemetry.io/otel/attribute"...)...var tracer = otel.Tracer("rolldice") // Create a Tracer....func (s *Server) rollDice(w http.ResponseWriter, req *http.Request) {ctx, span := tracer.Start(req.Context(), "roll") // Create a span.defer span.End()n := s.rand.Intn(6) + 1_, err := s.db.ExecContext(ctx, "INSERT INTO results (roll_value) VALUES (?)", n)if err != nil {panic(err)}span.SetAttributes(attribute.Int("roll.value", n)) // Add span attributes.fmt.Fprintf(w, "%v", n)}
net/http
and database/sql
of the Go language.package mainimport ("database/sql""fmt""net/http""os"_ "github.com/mattn/go-sqlite3""go.uber.org/zap")const (sqlQuery = "SELECT * FROM contacts"dbName = "test.db"tableDefinition = `CREATE TABLE contacts (contact_id INTEGER PRIMARY KEY,first_name TEXT NOT NULL,last_name TEXT NOT NULL,email TEXT NOT NULL,phone TEXT NOT NULL);`tableInsertion = `INSERT INTO 'contacts'('first_name', 'last_name', 'email', 'phone') VALUES('Moshe', 'Levi', 'moshe@gmail.com', '052-1234567');`)type Server struct {db *sql.DB}// Initialize the database.func CreateDb() {file, err := os.Create(dbName)if err != nil {panic(err)}err = file.Close()if err != nil {panic(err)}}func NewServer() *Server {CreateDb()database, err := sql.Open("sqlite3", dbName)if err != nil {panic(err)}_, err = database.Exec(tableDefinition)if err != nil {panic(err)}return &Server{db: database,}}func (s *Server) queryDb(w http.ResponseWriter, req *http.Request) {ctx := req.Context()conn, err := s.db.Conn(ctx)if err != nil {panic(err)}// Note that you must passctx
orreq.Context()
here to ensure that the HTTP request and database operation records can be maintained in the same trace.// If the request context is not passed here and it is written ass.db.Exec(tableInsertion)
, the trace will be interrupted, and the HTTP span and database span will appear in two separate traces!_, err = s.db.ExecContext(ctx, tableInsertion)if err != nil {panic(err)}rows, err := conn.QueryContext(req.Context(), sqlQuery)if err != nil {panic(err)}logger.Info("queryDb called")for rows.Next() {var id intvar firstName stringvar lastName stringvar email stringvar phone stringerr := rows.Scan(&id, &firstName, &lastName, &email, &phone)if err != nil {panic(err)}fmt.Fprintf(w, "ID: %d, firstName: %s, lastName: %s, email: %s, phone: %s\n", id, firstName, lastName, email, phone)}}