1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2024-11-21 16:46:38 +02:00

Run website formatter over website_docs (#3762)

* Run website formatter over website_docs

* Ignore selected website_docs links
This commit is contained in:
Patrice Chalin 2023-02-24 08:35:24 -05:00 committed by GitHub
parent 69d09462db
commit 3d6a643980
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 300 additions and 109 deletions

View File

@ -2,3 +2,5 @@ http://localhost
http://jaeger-collector
https://github.com/open-telemetry/opentelemetry-go/milestone/
https://github.com/open-telemetry/opentelemetry-go/projects
file:///home/runner/work/opentelemetry-go/opentelemetry-go/libraries
file:///home/runner/work/opentelemetry-go/opentelemetry-go/manual

View File

@ -1,8 +1,8 @@
---
title: Go
description: >-
<img width="35" src="/img/logos/32x32/Golang_SDK.svg" alt="Go"></img> A
language-specific implementation of OpenTelemetry in Go.
<img width="35" class="img-initial" src="/img/logos/32x32/Golang_SDK.svg"
alt="Go"></img> A language-specific implementation of OpenTelemetry in Go.
aliases: [/golang, /golang/metrics, /golang/tracing]
cascade:
github_repo: &repo https://github.com/open-telemetry/opentelemetry-go

View File

@ -5,8 +5,8 @@ weight: 4
---
In order to visualize and analyze your
[traces](/docs/concepts/signals/traces/#tracing-in-opentelemetry) and metrics, you
will need to export them to a backend.
[traces](/docs/concepts/signals/traces/#tracing-in-opentelemetry) and metrics,
you will need to export them to a backend.
## OTLP Exporter

View File

@ -1,15 +1,26 @@
---
title: "Getting Started"
title: Getting Started
weight: 2
---
Welcome to the OpenTelemetry for Go getting started guide! This guide will walk you through the basic steps in installing, instrumenting with, configuring, and exporting data from OpenTelemetry. Before you get started, be sure to have Go 1.16 or newer installed.
Welcome to the OpenTelemetry for Go getting started guide! This guide will walk
you through the basic steps in installing, instrumenting with, configuring, and
exporting data from OpenTelemetry. Before you get started, be sure to have Go
1.16 or newer installed.
Understanding how a system is functioning when it is failing or having issues is critical to resolving those issues. One strategy to understand this is with tracing. This guide shows how the OpenTelemetry Go project can be used to trace an example application. You will start with an application that computes Fibonacci numbers for users, and from there you will add instrumentation to produce tracing telemetry with OpenTelemetry Go.
Understanding how a system is functioning when it is failing or having issues is
critical to resolving those issues. One strategy to understand this is with
tracing. This guide shows how the OpenTelemetry Go project can be used to trace
an example application. You will start with an application that computes
Fibonacci numbers for users, and from there you will add instrumentation to
produce tracing telemetry with OpenTelemetry Go.
For reference, a complete example of the code you will build can be found [here](https://github.com/open-telemetry/opentelemetry-go/tree/main/example/fib).
For reference, a complete example of the code you will build can be found
[here](https://github.com/open-telemetry/opentelemetry-go/tree/main/example/fib).
To start building the application, make a new directory named `fib` to house our Fibonacci project. Next, add the following to a new file named `fib.go` in that directory.
To start building the application, make a new directory named `fib` to house our
Fibonacci project. Next, add the following to a new file named `fib.go` in that
directory.
```go
package main
@ -29,7 +40,8 @@ func Fibonacci(n uint) (uint64, error) {
}
```
With your core logic added, you can now build your application around it. Add a new `app.go` file with the following application logic.
With your core logic added, you can now build your application around it. Add a
new `app.go` file with the following application logic.
```go
package main
@ -84,7 +96,8 @@ func (a *App) Write(ctx context.Context, n uint) {
}
```
With your application fully composed, you need a `main()` function to actually run the application. In a new `main.go` file add the following run logic.
With your application fully composed, you need a `main()` function to actually
run the application. In a new `main.go` file add the following run logic.
```go
package main
@ -120,9 +133,13 @@ func main() {
}
```
With the code complete it is almost time to run the application. Before you can do that you need to initialize this directory as a Go module. From your terminal, run the command `go mod init fib` in the `fib` directory. This will create a `go.mod` file, which is used by Go to manage imports. Now you should be able to run the application!
With the code complete it is almost time to run the application. Before you can
do that you need to initialize this directory as a Go module. From your
terminal, run the command `go mod init fib` in the `fib` directory. This will
create a `go.mod` file, which is used by Go to manage imports. Now you should be
able to run the application!
```sh
```console
$ go run .
What Fibonacci number would you like to know:
42
@ -132,20 +149,27 @@ What Fibonacci number would you like to know:
goodbye
```
The application can be exited with CTRL+C. You should see a similar output as above, if not make sure to go back and fix any errors.
The application can be exited with <kbd>Ctrl+C</kbd>. You should see a similar
output as above, if not make sure to go back and fix any errors.
## Trace Instrumentation
OpenTelemetry is split into two parts: an API to instrument code with, and SDKs that implement the API. To start integrating OpenTelemetry into any project, the API is used to define how telemetry is generated. To generate tracing telemetry in your application you will use the OpenTelemetry Trace API from the [`go.opentelemetry.io/otel/trace`] package.
OpenTelemetry is split into two parts: an API to instrument code with, and SDKs
that implement the API. To start integrating OpenTelemetry into any project, the
API is used to define how telemetry is generated. To generate tracing telemetry
in your application you will use the OpenTelemetry Trace API from the
[`go.opentelemetry.io/otel/trace`] package.
First, you need to install the necessary packages for the Trace API. Run the following command in your working directory.
First, you need to install the necessary packages for the Trace API. Run the
following command in your working directory.
```sh
go get go.opentelemetry.io/otel \
go.opentelemetry.io/otel/trace
```
Now that the packages installed you can start updating your application with imports you will use in the `app.go` file.
Now that the packages installed you can start updating your application with
imports you will use in the `app.go` file.
```go
import (
@ -163,22 +187,41 @@ import (
With the imports added, you can start instrumenting.
The OpenTelemetry Tracing API provides a [`Tracer`] to create traces. These [`Tracer`]s are designed to be associated with one instrumentation library. That way telemetry they produce can be understood to come from that part of a code base. To uniquely identify your application to the [`Tracer`] you will use create a constant with the package name in `app.go`.
The OpenTelemetry Tracing API provides a [`Tracer`] to create traces. These
[`Tracer`]s are designed to be associated with one instrumentation library. That
way telemetry they produce can be understood to come from that part of a code
base. To uniquely identify your application to the [`Tracer`] you will use
create a constant with the package name in `app.go`.
```go
// name is the Tracer name used to identify this instrumentation library.
const name = "fib"
```
Using the full-qualified package name, something that should be unique for Go packages, is the standard way to identify a [`Tracer`]. If your example package name differs, be sure to update the name you use here to match.
Using the full-qualified package name, something that should be unique for Go
packages, is the standard way to identify a [`Tracer`]. If your example package
name differs, be sure to update the name you use here to match.
Everything should be in place now to start tracing your application. But first, what is a trace? And, how exactly should you build them for your application?
Everything should be in place now to start tracing your application. But first,
what is a trace? And, how exactly should you build them for your application?
To back up a bit, a trace is a type of telemetry that represents work being done by a service. A trace is a record of the connection(s) between participants processing a transaction, often through client/server requests processing and other forms of communication.
To back up a bit, a trace is a type of telemetry that represents work being done
by a service. A trace is a record of the connection(s) between participants
processing a transaction, often through client/server requests processing and
other forms of communication.
Each part of the work that a service performs is represented in the trace by a span. Those spans are not just an unordered collection. Like the call stack of our application, those spans are defined with relationships to one another. The "root" span is the only span without a parent, it represents how a service request is started. All other spans have a parent relationship to another span in the same trace.
Each part of the work that a service performs is represented in the trace by a
span. Those spans are not just an unordered collection. Like the call stack of
our application, those spans are defined with relationships to one another. The
"root" span is the only span without a parent, it represents how a service
request is started. All other spans have a parent relationship to another span
in the same trace.
If this last part about span relationships doesn't make complete sense now, don't worry. The most important takeaway is that each part of your code, which does some work, should be represented as a span. You will have a better understanding of these span relationships after you instrument your code, so let's get started.
If this last part about span relationships doesn't make complete sense now,
don't worry. The most important takeaway is that each part of your code, which
does some work, should be represented as a span. You will have a better
understanding of these span relationships after you instrument your code, so
let's get started.
Start by instrumenting the `Run` method.
@ -201,7 +244,14 @@ func (a *App) Run(ctx context.Context) error {
}
```
The above code creates a span for every iteration of the for loop. The span is created using a [`Tracer`] from the [global `TracerProvider`](https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider). You will learn more about [`TracerProvider`]s and handle the other side of setting up a global [`TracerProvider`] when you install an SDK in a later section. For now, as an instrumentation author, all you need to worry about is that you are using an appropriately named [`Tracer`] from a [`TracerProvider`] when you write `otel.Tracer(name)`.
The above code creates a span for every iteration of the for loop. The span is
created using a [`Tracer`] from the
[global `TracerProvider`](https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider).
You will learn more about [`TracerProvider`]s and handle the other side of
setting up a global [`TracerProvider`] when you install an SDK in a later
section. For now, as an instrumentation author, all you need to worry about is
that you are using an appropriately named [`Tracer`] from a [`TracerProvider`]
when you write `otel.Tracer(name)`.
Next, instrument the `Poll` method.
@ -224,7 +274,11 @@ func (a *App) Poll(ctx context.Context) (uint, error) {
}
```
Similar to the `Run` method instrumentation, this adds a span to the method to track the computation performed. However, it also adds an attribute to annotate the span. This annotation is something you can add when you think a user of your application will want to see the state or details about the run environment when looking at telemetry.
Similar to the `Run` method instrumentation, this adds a span to the method to
track the computation performed. However, it also adds an attribute to annotate
the span. This annotation is something you can add when you think a user of your
application will want to see the state or details about the run environment when
looking at telemetry.
Finally, instrument the `Write` method.
@ -248,9 +302,20 @@ func (a *App) Write(ctx context.Context, n uint) {
}
```
This method is instrumented with two spans. One to track the `Write` method itself, and another to track the call to the core logic with the `Fibonacci` function. Do you see how context is passed through the spans? Do you see how this also defines the relationship between spans?
This method is instrumented with two spans. One to track the `Write` method
itself, and another to track the call to the core logic with the `Fibonacci`
function. Do you see how context is passed through the spans? Do you see how
this also defines the relationship between spans?
In OpenTelemetry Go the span relationships are defined explicitly with a `context.Context`. When a span is created a context is returned alongside the span. That context will contain a reference to the created span. If that context is used when creating another span the two spans will be related. The original span will become the new span's parent, and as a corollary, the new span is said to be a child of the original. This hierarchy gives traces structure, structure that helps show a computation path through a system. Based on what you instrumented above and this understanding of span relationships you should expect a trace for each execution of the run loop to look like this.
In OpenTelemetry Go the span relationships are defined explicitly with a
`context.Context`. When a span is created a context is returned alongside the
span. That context will contain a reference to the created span. If that context
is used when creating another span the two spans will be related. The original
span will become the new span's parent, and as a corollary, the new span is said
to be a child of the original. This hierarchy gives traces structure, structure
that helps show a computation path through a system. Based on what you
instrumented above and this understanding of span relationships you should
expect a trace for each execution of the run loop to look like this.
```
Run
@ -259,17 +324,25 @@ Run
└── Fibonacci
```
A `Run` span will be a parent to both a `Poll` and `Write` span, and the `Write` span will be a parent to a `Fibonacci` span.
A `Run` span will be a parent to both a `Poll` and `Write` span, and the `Write`
span will be a parent to a `Fibonacci` span.
Now how do you actually see the produced spans? To do this you will need to configure and install an SDK.
Now how do you actually see the produced spans? To do this you will need to
configure and install an SDK.
## SDK Installation
OpenTelemetry is designed to be modular in its implementation of the OpenTelemetry API. The OpenTelemetry Go project offers an SDK package, [`go.opentelemetry.io/otel/sdk`], that implements this API and adheres to the OpenTelemetry specification. To start using this SDK you will first need to create an exporter, but before anything can happen we need to install some packages. Run the following in the `fib` directory to install the trace STDOUT exporter and the SDK.
OpenTelemetry is designed to be modular in its implementation of the
OpenTelemetry API. The OpenTelemetry Go project offers an SDK package,
[`go.opentelemetry.io/otel/sdk`], that implements this API and adheres to the
OpenTelemetry specification. To start using this SDK you will first need to
create an exporter, but before anything can happen we need to install some
packages. Run the following in the `fib` directory to install the trace STDOUT
exporter and the SDK.
```sh
$ go get go.opentelemetry.io/otel/sdk \
go.opentelemetry.io/otel/exporters/stdout/stdouttrace
go get go.opentelemetry.io/otel/sdk \
go.opentelemetry.io/otel/exporters/stdout/stdouttrace
```
Now add the needed imports to `main.go`.
@ -293,9 +366,17 @@ import (
### Creating a Console Exporter
The SDK connects telemetry from the OpenTelemetry API to exporters. Exporters are packages that allow telemetry data to be emitted somewhere - either to the console (which is what we're doing here), or to a remote system or collector for further analysis and/or enrichment. OpenTelemetry supports a variety of exporters through its ecosystem including popular open source tools like [Jaeger](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/jaeger), [Zipkin](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/zipkin), and [Prometheus](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/prometheus).
The SDK connects telemetry from the OpenTelemetry API to exporters. Exporters
are packages that allow telemetry data to be emitted somewhere - either to the
console (which is what we're doing here), or to a remote system or collector for
further analysis and/or enrichment. OpenTelemetry supports a variety of
exporters through its ecosystem including popular open source tools like
[Jaeger](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/jaeger),
[Zipkin](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/zipkin), and
[Prometheus](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/prometheus).
To initialize the console exporter, add the following function to the `main.go` file:
To initialize the console exporter, add the following function to the `main.go`
file:
```go
// newExporter returns a console exporter.
@ -310,11 +391,17 @@ func newExporter(w io.Writer) (trace.SpanExporter, error) {
}
```
This creates a new console exporter with basic options. You will use this function later when you configure the SDK to send telemetry data to it, but first you need to make sure that data is identifiable.
This creates a new console exporter with basic options. You will use this
function later when you configure the SDK to send telemetry data to it, but
first you need to make sure that data is identifiable.
### Creating a Resource
Telemetry data can be crucial to solving issues with a service. The catch is, you need a way to identify what service, or even what service instance, that data is coming from. OpenTelemetry uses a [`Resource`] to represent the entity producing telemetry. Add the following function to the `main.go` file to create an appropriate [`Resource`] for the application.
Telemetry data can be crucial to solving issues with a service. The catch is,
you need a way to identify what service, or even what service instance, that
data is coming from. OpenTelemetry uses a [`Resource`] to represent the entity
producing telemetry. Add the following function to the `main.go` file to create
an appropriate [`Resource`] for the application.
```go
// newResource returns a resource describing this application.
@ -332,13 +419,22 @@ func newResource() *resource.Resource {
}
```
Any information you would like to associate with all telemetry data the SDK handles can be added to the returned [`Resource`]. This is done by registering the [`Resource`] with the [`TracerProvider`]. Something you can now create!
Any information you would like to associate with all telemetry data the SDK
handles can be added to the returned [`Resource`]. This is done by registering
the [`Resource`] with the [`TracerProvider`]. Something you can now create!
### Installing a Tracer Provider
You have your application instrumented to produce telemetry data and you have an exporter to send that data to the console, but how are they connected? This is where the [`TracerProvider`] is used. It is a centralized point where instrumentation will get a [`Tracer`] from and funnels the telemetry data from these [`Tracer`]s to export pipelines.
You have your application instrumented to produce telemetry data and you have an
exporter to send that data to the console, but how are they connected? This is
where the [`TracerProvider`] is used. It is a centralized point where
instrumentation will get a [`Tracer`] from and funnels the telemetry data from
these [`Tracer`]s to export pipelines.
The pipelines that receive and ultimately transmit data to exporters are called [`SpanProcessor`]s. A [`TracerProvider`] can be configured to have multiple span processors, but for this example you will only need to configure only one. Update your `main` function in `main.go` with the following.
The pipelines that receive and ultimately transmit data to exporters are called
[`SpanProcessor`]s. A [`TracerProvider`] can be configured to have multiple span
processors, but for this example you will only need to configure only one.
Update your `main` function in `main.go` with the following.
```go
func main() {
@ -371,15 +467,30 @@ func main() {
}
```
There's a fair amount going on here. First you are creating a console exporter that will export to a file. You are then registering the exporter with a new [`TracerProvider`]. This is done with a [`BatchSpanProcessor`] when it is passed to the [`trace.WithBatcher`] option. Batching data is a good practice and will help not overload systems downstream. Finally, with the [`TracerProvider`] created, you are deferring a function to flush and stop it, and registering it as the global OpenTelemetry [`TracerProvider`].
There's a fair amount going on here. First you are creating a console exporter
that will export to a file. You are then registering the exporter with a new
[`TracerProvider`]. This is done with a [`BatchSpanProcessor`] when it is passed
to the [`trace.WithBatcher`] option. Batching data is a good practice and will
help not overload systems downstream. Finally, with the [`TracerProvider`]
created, you are deferring a function to flush and stop it, and registering it
as the global OpenTelemetry [`TracerProvider`].
Do you remember in the previous instrumentation section when we used the global [`TracerProvider`] to get a [`Tracer`]? This last step, registering the [`TracerProvider`] globally, is what will connect that instrumentation's [`Tracer`] with this [`TracerProvider`]. This pattern, using a global [`TracerProvider`], is convenient, but not always appropriate. [`TracerProvider`]s can be explicitly passed to instrumentation or inferred from a context that contains a span. For this simple example using a global provider makes sense, but for more complex or distributed codebases these other ways of passing [`TracerProvider`]s may make more sense.
Do you remember in the previous instrumentation section when we used the global
[`TracerProvider`] to get a [`Tracer`]? This last step, registering the
[`TracerProvider`] globally, is what will connect that instrumentation's
[`Tracer`] with this [`TracerProvider`]. This pattern, using a global
[`TracerProvider`], is convenient, but not always appropriate.
[`TracerProvider`]s can be explicitly passed to instrumentation or inferred from
a context that contains a span. For this simple example using a global provider
makes sense, but for more complex or distributed codebases these other ways of
passing [`TracerProvider`]s may make more sense.
## Putting It All Together
You should now have a working application that produces trace telemetry data! Give it a try.
You should now have a working application that produces trace telemetry data!
Give it a try.
```sh
```console
$ go run .
What Fibonacci number would you like to know:
42
@ -389,13 +500,16 @@ What Fibonacci number would you like to know:
goodbye
```
A new file named `traces.txt` should be created in your working directory. All the traces created from running your application should be in there!
A new file named `traces.txt` should be created in your working directory. All
the traces created from running your application should be in there!
## (Bonus) Errors
At this point you have a working application and it is producing tracing telemetry data. Unfortunately, it was discovered that there is an error in the core functionality of the `fib` module.
At this point you have a working application and it is producing tracing
telemetry data. Unfortunately, it was discovered that there is an error in the
core functionality of the `fib` module.
```sh
```console
$ go run .
What Fibonacci number would you like to know:
100
@ -403,7 +517,10 @@ Fibonacci(100) = 3736710778780434371
# …
```
But the 100-th Fibonacci number is `354224848179261915075`, not `3736710778780434371`! This application is only meant as a demo, but it shouldn't return wrong values. Update the `Fibonacci` function to return an error instead of computing incorrect values.
But the 100-th Fibonacci number is `354224848179261915075`, not
`3736710778780434371`! This application is only meant as a demo, but it
shouldn't return wrong values. Update the `Fibonacci` function to return an
error instead of computing incorrect values.
```go
// Fibonacci returns the n-th fibonacci number. An error is returned if the
@ -426,7 +543,9 @@ func Fibonacci(n uint) (uint64, error) {
}
```
Great, you have fixed the code, but it would be ideal to include errors returned to a user in the telemetry data. Luckily, spans can be configured to communicate this information. Update the `Write` method in `app.go` with the following code.
Great, you have fixed the code, but it would be ideal to include errors returned
to a user in the telemetry data. Luckily, spans can be configured to communicate
this information. Update the `Write` method in `app.go` with the following code.
```go
// Write writes the n-th Fibonacci number back to the user.
@ -449,9 +568,13 @@ func (a *App) Write(ctx context.Context, n uint) {
}
```
With this change any error returned from the `Fibonacci` function will mark that span as an error and record an event describing the error.
With this change any error returned from the `Fibonacci` function will mark that
span as an error and record an event describing the error.
This is a great start, but it is not the only error returned in from the application. If a user makes a request for a non unsigned integer value the application will fail. Update the `Poll` method with a similar fix to capture this error in the telemetry data.
This is a great start, but it is not the only error returned in from the
application. If a user makes a request for a non unsigned integer value the
application will fail. Update the `Poll` method with a similar fix to capture
this error in the telemetry data.
```go
// Poll asks a user for input and returns the request.
@ -477,7 +600,8 @@ func (a *App) Poll(ctx context.Context) (uint, error) {
}
```
All that is left is updating imports for the `app.go` file to include the [`go.opentelemetry.io/otel/codes`] package.
All that is left is updating imports for the `app.go` file to include the
[`go.opentelemetry.io/otel/codes`] package.
```go
import (
@ -496,7 +620,7 @@ import (
With these fixes in place and the instrumentation updated, re-trigger the bug.
```sh
```console
$ go run .
What Fibonacci number would you like to know:
100
@ -506,9 +630,11 @@ What Fibonacci number would you like to know:
goodbye
```
Excellent! The application no longer returns wrong values, and looking at the telemetry data in the `traces.txt` file you should see the error captured as an event.
Excellent! The application no longer returns wrong values, and looking at the
telemetry data in the `traces.txt` file you should see the error captured as an
event.
```
```json
"Events": [
{
"Name": "exception",
@ -545,15 +671,23 @@ For more information about instrumenting your code and things you can do with
spans, refer to the [manual instrumentation](/docs/instrumentation/go/manual/)
documentation.
You'll also want to configure an appropriate exporter to [export your telemetry
data](/docs/instrumentation/go/exporters) to one or more telemetry backends.
You'll also want to configure an appropriate exporter to
[export your telemetry data](/docs/instrumentation/go/exporters/) to one or more
telemetry backends.
[`go.opentelemetry.io/otel/trace`]: https://pkg.go.dev/go.opentelemetry.io/otel/trace
[`go.opentelemetry.io/otel/sdk`]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk
[`go.opentelemetry.io/otel/codes`]: https://pkg.go.dev/go.opentelemetry.io/otel/codes
[`Tracer`]: https://pkg.go.dev/go.opentelemetry.io/otel/trace#Tracer
[`TracerProvider`]: https://pkg.go.dev/go.opentelemetry.io/otel/trace#TracerProvider
[`Resource`]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource#Resource
[`SpanProcessor`]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#SpanProcessor
[`BatchSpanProcessor`]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#NewBatchSpanProcessor
[`trace.WithBatcher`]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#WithBatcher
[`go.opentelemetry.io/otel/trace`]:
https://pkg.go.dev/go.opentelemetry.io/otel/trace
[`go.opentelemetry.io/otel/sdk`]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk
[`go.opentelemetry.io/otel/codes`]:
https://pkg.go.dev/go.opentelemetry.io/otel/codes
[`tracer`]: https://pkg.go.dev/go.opentelemetry.io/otel/trace#Tracer
[`tracerprovider`]:
https://pkg.go.dev/go.opentelemetry.io/otel/trace#TracerProvider
[`resource`]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource#Resource
[`spanprocessor`]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#SpanProcessor
[`batchspanprocessor`]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#NewBatchSpanProcessor
[`trace.withbatcher`]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#WithBatcher

View File

@ -1,29 +1,39 @@
---
title: Using instrumentation libraries
weight: 3
linkTitle: Libraries
aliases: [/docs/instrumentation/go/using_instrumentation_libraries, /docs/instrumentation/go/automatic_instrumentation]
aliases:
- /docs/instrumentation/go/using_instrumentation_libraries
- /docs/instrumentation/go/automatic_instrumentation
weight: 3
---
Go does not support truly automatic instrumentation like other languages today. Instead, you'll need to depend on [instrumentation libraries](/docs/reference/specification/glossary/#instrumentation-library) that generate telemetry data for a particular instrumented library. For example, the instrumentation library for `net/http` will automatically create spans that track inbound and outbound requests once you configure it in your code.
Go does not support truly automatic instrumentation like other languages today.
Instead, you'll need to depend on
[instrumentation libraries](/docs/reference/specification/glossary/#instrumentation-library)
that generate telemetry data for a particular instrumented library. For example,
the instrumentation library for `net/http` will automatically create spans that
track inbound and outbound requests once you configure it in your code.
## Setup
Each instrumentation library is a package. In general, this means you need to `go get` the appropriate package:
Each instrumentation library is a package. In general, this means you need to
`go get` the appropriate package:
```console
```sh
go get go.opentelemetry.io/contrib/instrumentation/{import-path}/otel{package-name}
```
And then configure it in your code based on what the library requires to be activated.
And then configure it in your code based on what the library requires to be
activated.
## Example with `net/http`
As an example, here's how you can set up automatic instrumentation for inbound HTTP requests for `net/http`:
As an example, here's how you can set up automatic instrumentation for inbound
HTTP requests for `net/http`:
First, get the `net/http` instrumentation library:
```console
```sh
go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
```
@ -76,13 +86,18 @@ func main() {
}
```
Assuming that you have a `Tracer` and [exporter]({{< relref "exporters" >}}) configured, this code will:
Assuming that you have a `Tracer` and [exporter](../exporters/) configured, this
code will:
* Start an HTTP server on port `3030`
* Automatically generate a span for each inbound HTTP request to `/hello-instrumented`
* Create a child span of the automatically-generated one that tracks the work done in `sleepy`
- Start an HTTP server on port `3030`
- Automatically generate a span for each inbound HTTP request to
`/hello-instrumented`
- Create a child span of the automatically-generated one that tracks the work
done in `sleepy`
Connecting manual instrumentation you write in your app with instrumentation generated from a library is essential to get good observability into your apps and services.
Connecting manual instrumentation you write in your app with instrumentation
generated from a library is essential to get good observability into your apps
and services.
## Available packages
@ -91,6 +106,9 @@ A full list of instrumentation libraries available can be found in the
## Next steps
Instrumentation libraries can do things like generate telemetry data for inbound and outbound HTTP requests, but they don't instrument your actual application.
Instrumentation libraries can do things like generate telemetry data for inbound
and outbound HTTP requests, but they don't instrument your actual application.
To get richer telemetry data, use [manual instrumentation]({{< relref "manual" >}}) to enrich your telemetry data from instrumentation libraries with instrumentation from your running application.
To get richer telemetry data, use [manual instrumentation](../manual/) to enrich
your telemetry data from instrumentation libraries with instrumentation from
your running application.

View File

@ -1,11 +1,15 @@
---
title: Manual Instrumentation
weight: 3
linkTitle: Manual
aliases: [/docs/instrumentation/go/instrumentation, /docs/instrumentation/go/manual_instrumentation]
aliases:
- /docs/instrumentation/go/instrumentation
- /docs/instrumentation/go/manual_instrumentation
weight: 3
---
Instrumentation is the process of adding observability code to your application. There are two general types of instrumentation - automatic, and manual - and you should be familiar with both in order to effectively instrument your software.
Instrumentation is the process of adding observability code to your application.
There are two general types of instrumentation - automatic, and manual - and you
should be familiar with both in order to effectively instrument your software.
## Getting a Tracer
@ -15,7 +19,7 @@ To create spans, you'll need to acquire or initialize a tracer first.
Ensure you have the right packages installed:
```
```sh
go get go.opentelemetry.io/otel \
go.opentelemetry.io/otel/trace \
go.opentelemetry.io/otel/sdk \
@ -54,7 +58,7 @@ func newTraceProvider(exp sdktrace.SpanExporter) *sdktrace.TracerProvider {
semconv.ServiceName("ExampleService"),
),
)
if err != nil {
panic(err)
}
@ -90,9 +94,12 @@ You can now access `tracer` to manually instrument your code.
## Creating Spans
Spans are created by tracers. If you don't have one initialized, you'll need to do that.
Spans are created by tracers. If you don't have one initialized, you'll need to
do that.
To create a span with a tracer, you'll also need a handle on a `context.Context` instance. These will typically come from things like a request object and may already contain a parent span from an [instrumentation library][].
To create a span with a tracer, you'll also need a handle on a `context.Context`
instance. These will typically come from things like a request object and may
already contain a parent span from an [instrumentation library][].
```go
func httpHandler(w http.ResponseWriter, r *http.Request) {
@ -103,13 +110,16 @@ func httpHandler(w http.ResponseWriter, r *http.Request) {
}
```
In Go, the `context` package is used to store the active span. When you start a span, you'll get a handle on not only the span that's created, but the modified context that contains it.
In Go, the `context` package is used to store the active span. When you start a
span, you'll get a handle on not only the span that's created, but the modified
context that contains it.
Once a span has completed, it is immutable and can no longer be modified.
### Get the current span
To get the current span, you'll need to pull it out of a `context.Context` you have a handle on:
To get the current span, you'll need to pull it out of a `context.Context` you
have a handle on:
```go
// This context needs contain the active span you plan to extract.
@ -119,13 +129,15 @@ span := trace.SpanFromContext(ctx)
// Do something with the current span, optionally calling `span.End()` if you want it to end
```
This can be helpful if you'd like to add information to the current span at a point in time.
This can be helpful if you'd like to add information to the current span at a
point in time.
### Create nested spans
You can create a nested span to track work in a nested operation.
If the current `context.Context` you have a handle on already contains a span inside of it, creating a new span makes it a nested span. For example:
If the current `context.Context` you have a handle on already contains a span
inside of it, creating a new span makes it a nested span. For example:
```go
func parentFunction(ctx context.Context) {
@ -151,7 +163,10 @@ Once a span has completed, it is immutable and can no longer be modified.
### Span Attributes
Attributes are keys and values that are applied as metadata to your spans and are useful for aggregating, filtering, and grouping traces. Attributes can be added at span creation, or at any other time during the lifecycle of a span before it has completed.
Attributes are keys and values that are applied as metadata to your spans and
are useful for aggregating, filtering, and grouping traces. Attributes can be
added at span creation, or at any other time during the lifecycle of a span
before it has completed.
```go
// setting attributes at creation...
@ -169,13 +184,21 @@ span.SetAttributes(myKey.String("a value"))
#### Semantic Attributes
Semantic Attributes are attributes that are defined by the [OpenTelemetry Specification][] in order to provide a shared set of attribute keys across multiple languages, frameworks, and runtimes for common concepts like HTTP methods, status codes, user agents, and more. These attributes are available in the `go.opentelemetry.io/otel/semconv/v1.12.0` package.
Semantic Attributes are attributes that are defined by the [OpenTelemetry
Specification][] in order to provide a shared set of attribute keys across
multiple languages, frameworks, and runtimes for common concepts like HTTP
methods, status codes, user agents, and more. These attributes are available in
the `go.opentelemetry.io/otel/semconv/v1.12.0` package.
For details, see [Trace semantic conventions][].
### Events
An event is a human-readable message on a span that represents "something happening" during it's lifetime. For example, imagine a function that requires exclusive access to a resource that is under a mutex. An event could be created at two points - once, when we try to gain access to the resource, and another when we acquire the mutex.
An event is a human-readable message on a span that represents "something
happening" during it's lifetime. For example, imagine a function that requires
exclusive access to a resource that is under a mutex. An event could be created
at two points - once, when we try to gain access to the resource, and another
when we acquire the mutex.
```go
span.AddEvent("Acquiring lock")
@ -186,7 +209,9 @@ span.AddEvent("Unlocking")
mutex.Unlock()
```
A useful characteristic of events is that their timestamps are displayed as offsets from the beginning of the span, allowing you to easily see how much time elapsed between them.
A useful characteristic of events is that their timestamps are displayed as
offsets from the beginning of the span, allowing you to easily see how much time
elapsed between them.
Events can also have attributes of their own -
@ -196,7 +221,8 @@ span.AddEvent("Cancelled wait due to external signal", trace.WithAttributes(attr
### Set span status
A status can be set on a span, typically used to specify that there was an error in the operation a span is tracking - .`Error`.
A status can be set on a span, typically used to specify that there was an error
in the operation a span is tracking - .`Error`.
```go
import (
@ -213,11 +239,13 @@ if err != nil {
}
```
By default, the status for all spans is `Unset`. In rare cases, you may also wish to set the status to `Ok`. This should generally not be necessary, though.
By default, the status for all spans is `Unset`. In rare cases, you may also
wish to set the status to `Ok`. This should generally not be necessary, though.
### Record errors
If you have an operation that failed and you wish to capture the error it produced, you can record that error.
If you have an operation that failed and you wish to capture the error it
produced, you can record that error.
```go
import (
@ -235,8 +263,10 @@ if err != nil {
}
```
It is highly recommended that you also set a span's status to `Error` when using `RecordError`, unless you do not wish to consider the span tracking a failed operation as an error span.
The `RecordError` function does **not** automatically set a span status when called.
It is highly recommended that you also set a span's status to `Error` when using
`RecordError`, unless you do not wish to consider the span tracking a failed
operation as an error span. The `RecordError` function does **not**
automatically set a span status when called.
## Creating Metrics
@ -244,9 +274,11 @@ The metrics API is currently unstable, documentation TBA.
## Propagators and Context
Traces can extend beyond a single process. This requires _context propagation_, a mechanism where identifiers for a trace are sent to remote processes.
Traces can extend beyond a single process. This requires _context propagation_,
a mechanism where identifiers for a trace are sent to remote processes.
In order to propagate trace context over the wire, a propagator must be registered with the OpenTelemetry API.
In order to propagate trace context over the wire, a propagator must be
registered with the OpenTelemetry API.
```go
import (
@ -257,10 +289,15 @@ import (
otel.SetTextMapPropagator(propagation.TraceContext{})
```
> OpenTelemetry also supports the B3 header format, for compatibility with existing tracing systems (`go.opentelemetry.io/contrib/propagators/b3`) that do not support the W3C TraceContext standard.
> OpenTelemetry also supports the B3 header format, for compatibility with
> existing tracing systems (`go.opentelemetry.io/contrib/propagators/b3`) that
> do not support the W3C TraceContext standard.
After configuring context propagation, you'll most likely want to use automatic instrumentation to handle the behind-the-scenes work of actually managing serializing the context.
After configuring context propagation, you'll most likely want to use automatic
instrumentation to handle the behind-the-scenes work of actually managing
serializing the context.
[OpenTelemetry Specification]: {{< relref "/docs/reference/specification" >}}
[Trace semantic conventions]: {{< relref "/docs/reference/specification/trace/semantic_conventions" >}}
[instrumentation library]: {{< relref "libraries" >}}
[opentelemetry specification]: /docs/reference/specification/
[trace semantic conventions]:
/docs/reference/specification/trace/semantic_conventions/
[instrumentation library]: ../libraries/

View File

@ -5,8 +5,8 @@ weight: 6
Resources are a special type of attribute that apply to all spans generated by a
process. These should be used to represent underlying metadata about a process
that's non-ephemeral - for example, the hostname of a process, or its instance
ID.
that's non-ephemeral &mdash; for example, the hostname of a process, or its
instance ID.
Resources should be assigned to a tracer provider at its initialization, and are
created much like attributes: