Skip to content

Commit

Permalink
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
Browse files Browse the repository at this point in the history
…trib into pool-metric-options

# Conflicts:
#	CHANGELOG.md
#	instrumentation/net/http/otelhttp/internal/semconv/env_test.go
  • Loading branch information
vordimous committed Dec 11, 2024
2 parents 1cf3683 + eb2064c commit 06c5578
Show file tree
Hide file tree
Showing 85 changed files with 5,439 additions and 695 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Added support exporting logs via OTLP over gRPC in `go.opentelemetry.io/contrib/config`. (#6340)
- The `go.opentelemetry.io/contrib/bridges/otellogr` module.
This module provides an OpenTelemetry logging bridge for `github.com/go-logr/logr`. (#6386)
- Added SNS instrumentation in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#6388)
- Use a pool for the semantic convention metrics options in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp`. (#6394)

### Changed

- Change the span name to be `GET /path` so it complies with the OTel HTTP semantic conventions in `go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho`. (#6365)
- Record errors instead of setting the `gin.errors` attribute in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#6346)
- The `go.opentelemetry.io/contrib/config` now supports multiple schemas in subdirectories (ie. `go.opentelemetry.io/contrib/config/v0.3.0`) for easier migration. (#6412)

### Fixed

- Fix broken AWS presigned URLs when using instrumentation in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#5975)
- Fixed the value for configuring the OTLP exporter to use `grpc` instead of `grpc/protobuf` in `go.opentelemetry.io/contrib/config`. (#6338)
- Allow marshaling types in `go.opentelemetry.io/contrib/config`. (#6347)
- Removed the redundant handling of panic from the `HTML` function in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#6373)
- The `code.function` attribute emitted by `go.opentelemetry.io/contrib/bridges/otelslog` now stores just the function name instead the package path-qualified function name. The `code.namespace` attribute now stores the package path. (#6415)

<!-- Released section -->
<!-- Don't change this section unless doing release -->
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,12 @@ OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_VERSION=v0.3.0
genjsonschema-cleanup:
rm -Rf ${OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_SRC_DIR}

GENERATED_CONFIG=./config/generated_config.go
GENERATED_CONFIG=./config/${OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_VERSION}/generated_config.go

# Generate structs for configuration from opentelemetry-configuration schema
genjsonschema: genjsonschema-cleanup $(GOJSONSCHEMA)
mkdir -p ${OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_SRC_DIR}
mkdir -p ./config/${OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_VERSION}
curl -sSL https://api.github.com/repos/open-telemetry/opentelemetry-configuration/tarball/${OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_VERSION} | tar xz --strip 1 -C ${OPENTELEMETRY_CONFIGURATION_JSONSCHEMA_SRC_DIR}
$(GOJSONSCHEMA) \
--capitalization ID \
Expand Down
17 changes: 16 additions & 1 deletion bridges/otelslog/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
"log/slog"
"runtime"
"slices"
"strings"

"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/global"
Expand Down Expand Up @@ -192,9 +193,11 @@ func (h *Handler) convertRecord(r slog.Record) log.Record {
if h.source {
fs := runtime.CallersFrames([]uintptr{r.PC})
f, _ := fs.Next()
funcName, namespace := splitFuncName(f.Function)
record.AddAttributes(
log.String(string(semconv.CodeFilepathKey), f.File),
log.String(string(semconv.CodeFunctionKey), f.Function),
log.String(string(semconv.CodeFunctionKey), funcName),
log.String(string(semconv.CodeNamespaceKey), namespace),
log.Int(string(semconv.CodeLineNumberKey), f.Line),
)
}
Expand Down Expand Up @@ -476,3 +479,15 @@ func convert(v slog.Value) log.Value {
return log.StringValue(fmt.Sprintf("unhandled: (%s) %+v", v.Kind(), v.Any()))
}
}

// splitFuncName splits package path-qualified function name into
// function name and package full name (namespace). E.g. it splits
// "github.com/my/repo/pkg.foo" into
// "foo" and "github.com/my/repo/pkg".
func splitFuncName(f string) (string, string) {
i := strings.LastIndexByte(f, '.')
if i < 0 {
return "", ""
}
return f[i+1:], f[:i]
}
52 changes: 51 additions & 1 deletion bridges/otelslog/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func (h *wrapper) Handle(ctx context.Context, r slog.Record) error {
func TestSLogHandler(t *testing.T) {
// Capture the PC of this line
pc, file, line, _ := runtime.Caller(0)
funcName := runtime.FuncForPC(pc).Name()
funcName, namespace := splitFuncName(runtime.FuncForPC(pc).Name())

cases := []testCase{
{
Expand Down Expand Up @@ -414,6 +414,7 @@ func TestSLogHandler(t *testing.T) {
checks: [][]check{{
hasAttr(string(semconv.CodeFilepathKey), file),
hasAttr(string(semconv.CodeFunctionKey), funcName),
hasAttr(string(semconv.CodeNamespaceKey), namespace),
hasAttr(string(semconv.CodeLineNumberKey), int64(line)),
}},
options: []Option{WithSource(true)},
Expand Down Expand Up @@ -510,6 +511,42 @@ func TestHandlerEnabled(t *testing.T) {
assert.True(t, h.Enabled(ctx, slog.LevelDebug), "context not passed")
}

func TestSplitFuncName(t *testing.T) {
testCases := []struct {
fullFuncName string
wantFuncName string
wantNamespace string
}{
{
fullFuncName: "github.com/my/repo/pkg.foo",
wantFuncName: "foo",
wantNamespace: "github.com/my/repo/pkg",
},
{
fullFuncName: "net/http.Get",
wantFuncName: "Get",
wantNamespace: "net/http",
},
{
fullFuncName: "invalid",
wantFuncName: "",
wantNamespace: "",
},
{
fullFuncName: ".",
wantFuncName: "",
wantNamespace: "",
},
}
for _, tc := range testCases {
t.Run(tc.fullFuncName, func(t *testing.T) {
gotFuncName, gotNamespace := splitFuncName(tc.fullFuncName)
assert.Equal(t, tc.wantFuncName, gotFuncName)
assert.Equal(t, tc.wantNamespace, gotNamespace)
})
}
}

func BenchmarkHandler(b *testing.B) {
var (
h slog.Handler
Expand Down Expand Up @@ -639,5 +676,18 @@ func BenchmarkHandler(b *testing.B) {
})
})

b.Run("(WithSource).Handle", func(b *testing.B) {
handlers := make([]*Handler, b.N)
for i := range handlers {
handlers[i] = NewHandler("", WithSource(true))
}

b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
err = handlers[n].Handle(ctx, record)
}
})

_, _ = h, err
}
9 changes: 6 additions & 3 deletions config/doc.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

// Package config can be used to parse a configuration file
// that follows the JSON Schema defined by the OpenTelemetry
// Configuration schema.
// Package config can be used to parse a configuration file that follows
// the JSON Schema defined by the OpenTelemetry Configuration schema. Different
// versions of the schema are supported by the code in the directory that
// matches the version number of the schema. For example, the import
// go.opentelemetry.io/contrib/config/v0.3.0 includes code that supports the
// v0.3.0 release of the configuration schema.
package config // import "go.opentelemetry.io/contrib/config"
4 changes: 2 additions & 2 deletions config/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ require (
golang.org/x/net v0.32.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/grpc v1.68.1 // indirect
google.golang.org/protobuf v1.35.2 // indirect
)
8 changes: 4 additions & 4 deletions config/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583 h1:v+j+5gpj0FopU0KKLDGfDo9ZRRpKdi5UBrCP0f76kuY=
google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 h1:IfdSdTcLFy4lqUQrQJLkLt1PB+AsqVz6lwkWPzWEz10=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
Expand Down
152 changes: 152 additions & 0 deletions config/v0.2.0/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package config // import "go.opentelemetry.io/contrib/config/v0.2.0"

import (
"context"
"errors"

"gopkg.in/yaml.v3"

"go.opentelemetry.io/otel/log"
nooplog "go.opentelemetry.io/otel/log/noop"
"go.opentelemetry.io/otel/metric"
noopmetric "go.opentelemetry.io/otel/metric/noop"
"go.opentelemetry.io/otel/trace"
nooptrace "go.opentelemetry.io/otel/trace/noop"
)

const (
protocolProtobufHTTP = "http/protobuf"
protocolProtobufGRPC = "grpc/protobuf"

compressionGzip = "gzip"
compressionNone = "none"
)

type configOptions struct {
ctx context.Context
opentelemetryConfig OpenTelemetryConfiguration
}

type shutdownFunc func(context.Context) error

func noopShutdown(context.Context) error {
return nil
}

// SDK is a struct that contains all the providers
// configured via the configuration model.
type SDK struct {
meterProvider metric.MeterProvider
tracerProvider trace.TracerProvider
loggerProvider log.LoggerProvider
shutdown shutdownFunc
}

// TracerProvider returns a configured trace.TracerProvider.
func (s *SDK) TracerProvider() trace.TracerProvider {
return s.tracerProvider
}

// MeterProvider returns a configured metric.MeterProvider.
func (s *SDK) MeterProvider() metric.MeterProvider {
return s.meterProvider
}

// LoggerProvider returns a configured log.LoggerProvider.
func (s *SDK) LoggerProvider() log.LoggerProvider {
return s.loggerProvider
}

// Shutdown calls shutdown on all configured providers.
func (s *SDK) Shutdown(ctx context.Context) error {
return s.shutdown(ctx)
}

var noopSDK = SDK{
loggerProvider: nooplog.LoggerProvider{},
meterProvider: noopmetric.MeterProvider{},
tracerProvider: nooptrace.TracerProvider{},
shutdown: func(ctx context.Context) error { return nil },
}

// NewSDK creates SDK providers based on the configuration model.
func NewSDK(opts ...ConfigurationOption) (SDK, error) {
o := configOptions{}
for _, opt := range opts {
o = opt.apply(o)
}
if o.opentelemetryConfig.Disabled != nil && *o.opentelemetryConfig.Disabled {
return noopSDK, nil
}

r, err := newResource(o.opentelemetryConfig.Resource)
if err != nil {
return noopSDK, err
}

mp, mpShutdown, err := meterProvider(o, r)
if err != nil {
return noopSDK, err
}

tp, tpShutdown, err := tracerProvider(o, r)
if err != nil {
return noopSDK, err
}

lp, lpShutdown, err := loggerProvider(o, r)
if err != nil {
return noopSDK, err
}

return SDK{
meterProvider: mp,
tracerProvider: tp,
loggerProvider: lp,
shutdown: func(ctx context.Context) error {
return errors.Join(mpShutdown(ctx), tpShutdown(ctx), lpShutdown(ctx))
},
}, nil
}

// ConfigurationOption configures options for providers.
type ConfigurationOption interface {
apply(configOptions) configOptions
}

type configurationOptionFunc func(configOptions) configOptions

func (fn configurationOptionFunc) apply(cfg configOptions) configOptions {
return fn(cfg)
}

// WithContext sets the context.Context for the SDK.
func WithContext(ctx context.Context) ConfigurationOption {
return configurationOptionFunc(func(c configOptions) configOptions {
c.ctx = ctx
return c
})
}

// WithOpenTelemetryConfiguration sets the OpenTelemetryConfiguration used
// to produce the SDK.
func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) ConfigurationOption {
return configurationOptionFunc(func(c configOptions) configOptions {
c.opentelemetryConfig = cfg
return c
})
}

// ParseYAML parses a YAML configuration file into an OpenTelemetryConfiguration.
func ParseYAML(file []byte) (*OpenTelemetryConfiguration, error) {
var cfg OpenTelemetryConfiguration
err := yaml.Unmarshal(file, &cfg)
if err != nil {
return nil, err
}

return &cfg, nil
}
Loading

0 comments on commit 06c5578

Please sign in to comment.