Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Go] Document logs #4463

Merged
merged 25 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 162 additions & 3 deletions content/en/docs/languages/go/instrumentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ aliases:
- manual_instrumentation
weight: 30
description: Manual instrumentation for OpenTelemetry Go
cSpell:ignore: fatalf otlptrace sdktrace sighup
cSpell:ignore: fatalf logr logrus otelslog otlplog otlploghttp sdktrace sighup
---

{{% docs/languages/instrumentation-intro %}}
Expand Down Expand Up @@ -37,7 +37,6 @@ import (
"log"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
Expand Down Expand Up @@ -876,7 +875,158 @@ meterProvider := metric.NewMeterProvider(

## Logs

The logs API is currently unstable, documentation TBA.
Logs are distinct from metrics and traces in that **there is no user-facing
OpenTelemetry logs API**. Instead, there is tooling to bridge logs from existing
popular log packages (such as slog, logrus, zap, logr) into the OpenTelemetry
ecosystem. For rationale behind this design decision, see
[Logging specification](/docs/specs/otel/logs/).

The two typical workflows discussed below each cater to different application
requirements.

### Direct to collector (Experimental)
pellared marked this conversation as resolved.
Show resolved Hide resolved

In the direct to collector workflow, logs are emitted directly from an
pellared marked this conversation as resolved.
Show resolved Hide resolved
application to a collector using a network protocol (e.g. OTLP). This workflow
is simple to set up as it doesn't require any additional log forwarding
components, and allows an application to easily emit structured logs that
conform to the [log data model][log data model]. However, the overhead required
for applications to queue and export logs to a network location may not be
suitable for all applications.

To use this workflow:

- Configure the OpenTelemetry [Log SDK](#logs-sdk-experimental) to export log
records to desired target destination (the
[collector][opentelemetry collector] or other).
- Use an appropriate [Log Bridge](#log-bridge-experimental).

#### Logs SDK (Experimental)
pellared marked this conversation as resolved.
Show resolved Hide resolved

The logs SDK dictates how logs are processed when using the
[direct to collector](#direct-to-collector-experimental) workflow. No log SDK is
needed when using the [log forwarding](#via-file-or-stdout) workflow.

The typical log SDK configuration installs a batching log record processor with
an OTLP exporter.

To enable [logs](/docs/concepts/signals/logs/) in your app, you'll need to have
an initialized [`LoggerProvider`](/docs/concepts/signals/logs/#logger-provider)
that will let you use a [Log Bridge](#log-bridge-experimental).

If a `LoggerProvider` is not created, the OpenTelemetry APIs for logs will use a
no-op implementation and fail to generate data. Therefore, you have to modify
the source code to include the SDK initialization code using the following
packages:

- [`go.opentelemetry.io/otel`][]
- [`go.opentelemetry.io/otel/sdk/log`][]
- [`go.opentelemetry.io/otel/sdk/resource`][]
- [`go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`][]

Ensure you have the right Go modules installed:

```sh
go get go.opentelemetry.io/otel \
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp \
go.opentelemetry.io/otel/sdk \
go.opentelemetry.io/otel/sdk/log
```

Then initialize a logger provider:

```go
package main

import (
"context"
"fmt"

"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)

func main() {
ctx := context.Background()

// Create resource.
res, err := newResource()
if err != nil {
panic(err)
}

// Create a logger provider.
// You can pass this instance directly when creating bridges.
loggerProvider, err := newLoggerProvider(ctx, res)
if err != nil {
panic(err)
}

// Handle shutdown properly so nothing leaks.
defer func() {
if err := loggerProvider.Shutdown(ctx); err != nil {
fmt.Println(err)
}
}()

// Register as global logger provider so that it can be accessed global.LoggerProvider.
// Most log bridges use the global logger provider as default.
// If the global logger provider is not set then a no-op implementation
// is used, which fails to generate data.
global.SetLoggerProvider(loggerProvider)
}

func newResource() (*resource.Resource, error) {
return resource.Merge(resource.Default(),
resource.NewWithAttributes(semconv.SchemaURL,
semconv.ServiceName("my-service"),
semconv.ServiceVersion("0.1.0"),
))
}

func newLoggerProvider(ctx context.Context, res *resource.Resource) (*log.LoggerProvider, error) {
exporter, err := otlploghttp.New(ctx)
if err != nil {
return nil, err
}
processor := log.NewBatchProcessor(exporter)
provider := log.NewLoggerProvider(
log.WithResource(res),
log.WithProcessor(processor),
)
return provider, nil
}
```

Now that a `LoggerProvider` is configured, you can use it to set up a
[Log Bridge](#log-bridge-experimental).

#### Log Bridge (Experimental)
pellared marked this conversation as resolved.
Show resolved Hide resolved

A log bridge is a component that bridges logs from an existing log package into
the OpenTelemetry [Log SDK](#logs-sdk-experimental) using the [Logs Bridge
API][logs bridge API]. Log bridges are available for various popular Go log
packages:

- [slog bridge][otelslog]

The links above contain full usage and installation documentation.

### Via file or stdout

In the file or stdout workflow, logs are written to files or standout output.
Another component (e.g. FluentBit) is responsible for reading / tailing the
logs, parsing them to more structured format, and forwarding them a target, such
as the collector. This workflow may be preferable in situations where
application requirements do not permit additional overhead from
[direct to collector](#direct-to-collector-experimental). However, it requires
that all log fields required down stream are encoded into the logs, and that the
component reading the logs parse the data into the [log data
model][log data model]. The installation and configuration of log forwarding
components is outside the scope of this document.

## Next Steps

Expand All @@ -887,11 +1037,20 @@ telemetry backends.
[opentelemetry specification]: /docs/specs/otel/
[trace semantic conventions]: /docs/specs/semconv/general/trace/
[instrumentation library]: ../libraries/
[opentelemetry collector]:
https://github.com/open-telemetry/opentelemetry-collector
[logs bridge API]: /docs/specs/otel/logs/bridge-api
[log data model]: /docs/specs/otel/logs/data-model
[otelslog]: https://pkg.go.dev/go.opentelemetry.io/contrib/bridges/otelslog
[`go.opentelemetry.io/otel`]: https://pkg.go.dev/go.opentelemetry.io/otel
[`go.opentelemetry.io/otel/exporters/stdout/stdoutmetric`]:
https://pkg.go.dev/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric
[`go.opentelemetry.io/otel/metric`]:
https://pkg.go.dev/go.opentelemetry.io/otel/metric
[`go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`]:
https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp
[`go.opentelemetry.io/otel/sdk/log`]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk/log
[`go.opentelemetry.io/otel/sdk/metric`]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric
[`go.opentelemetry.io/otel/sdk/resource`]:
Expand Down
4 changes: 2 additions & 2 deletions content/en/docs/languages/go/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ cSpell:ignore: sdktrace thirdparty

{{% docs/languages/resources-intro %}}

Resources should be assigned to a tracer provider at its initialization, and are
created much like attributes:
Resources should be assigned to a tracer, meter, and logger provider at its
initialization, and are created much like attributes:

```go
res := resource.NewWithAttributes(
Expand Down
8 changes: 8 additions & 0 deletions static/refcache.json
Original file line number Diff line number Diff line change
Expand Up @@ -6995,6 +6995,10 @@
"StatusCode": 200,
"LastSeen": "2024-03-01T16:49:37.76693+01:00"
},
"https://pkg.go.dev/go.opentelemetry.io/contrib/bridges/otelslog": {
"StatusCode": 200,
"LastSeen": "2024-05-10T11:02:15.508410781Z"
},
"https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp": {
"StatusCode": 200,
"LastSeen": "2024-01-19T15:36:28.468246594Z"
Expand Down Expand Up @@ -7059,6 +7063,10 @@
"StatusCode": 200,
"LastSeen": "2024-01-30T15:25:42.951557-05:00"
},
"https://pkg.go.dev/go.opentelemetry.io/otel/sdk/log": {
"StatusCode": 200,
"LastSeen": "2024-05-10T11:02:08.878761042Z"
},
"https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric": {
"StatusCode": 200,
"LastSeen": "2024-01-30T15:25:12.503352-05:00"
Expand Down