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:
parent
69d09462db
commit
3d6a643980
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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/
|
||||
|
@ -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 — 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:
|
||||
|
Loading…
Reference in New Issue
Block a user