Skip to content

Commit

Permalink
Merge branch 'open-telemetry:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Victorsesan authored Oct 19, 2024
2 parents 890e925 + 1c56a7c commit 21bc6b7
Show file tree
Hide file tree
Showing 41 changed files with 698 additions and 173 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Added

- Transform raw (`slog.KindAny`) attribute values to matching `log.Value` types.
For example, `[]string{"foo", "bar"}` attribute value is now transformed to `log.SliceValue(log.StringValue("foo"), log.StringValue("bar"))` instead of `log.String("[foo bar"])`. (#6254)
- Add the `WithSource` option to the `go.opentelemetry.io/contrib/bridges/otelslog` log bridge to set the `code.*` attributes in the log record that includes the source location where the record was emitted. (#6253)

### Fixed

- Transform nil attribute values to `log.Value` zero value instead of panicking in `go.opentelemetry.io/contrib/bridges/otellogrus`. (#6237)
- Transform nil attribute values to `log.Value` zero value instead of panicking in `go.opentelemetry.io/contrib/bridges/otelzap`. (#6237)
- Transform nil attribute values to `log.Value` zero value instead of `log.StringValue("<nil>")` in `go.opentelemetry.io/contrib/bridges/otelslog`. (#6246)
- Fix `NewClientHandler` so that `rpc.client.request.*` metrics measure requests instead of responses and `rpc.client.responses.*` metrics measure responses instead of requests in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#6250)
- Fix issue in `go.opentelemetry.io/contrib/config` causing `otelprom.WithResourceAsConstantLabels` configuration to not be respected. (#6260)

<!-- Released section -->
<!-- Don't change this section unless doing release -->
Expand Down
2 changes: 1 addition & 1 deletion bridges/otellogrus/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
// - [logrus.PanicLevel] is transformed to [log.SeverityFatal4]
//
// Field values are transformed based on their type into log attributes, or
// into a string value if there is no matching type.
// into a string value encoded using [fmt.Sprintf] if there is no matching type.
//
// [OpenTelemetry]: https://opentelemetry.io/docs/concepts/signals/logs/
package otellogrus // import "go.opentelemetry.io/contrib/bridges/otellogrus"
Expand Down
123 changes: 123 additions & 0 deletions bridges/otelslog/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Code created by gotmpl. DO NOT MODIFY.
// source: internal/shared/logutil/convert.go.tmpl

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package otelslog // import "go.opentelemetry.io/contrib/bridges/otelslog"

import (
"fmt"
"math"
"reflect"
"strconv"
"time"

"go.opentelemetry.io/otel/log"
)

// convertValue converts various types to log.Value.
func convertValue(v any) log.Value {
// Handling the most common types without reflect is a small perf win.
switch val := v.(type) {
case bool:
return log.BoolValue(val)
case string:
return log.StringValue(val)
case int:
return log.Int64Value(int64(val))
case int8:
return log.Int64Value(int64(val))
case int16:
return log.Int64Value(int64(val))
case int32:
return log.Int64Value(int64(val))
case int64:
return log.Int64Value(val)
case uint:
return convertUintValue(uint64(val))
case uint8:
return log.Int64Value(int64(val))
case uint16:
return log.Int64Value(int64(val))
case uint32:
return log.Int64Value(int64(val))
case uint64:
return convertUintValue(val)
case uintptr:
return convertUintValue(uint64(val))
case float32:
return log.Float64Value(float64(val))
case float64:
return log.Float64Value(val)
case time.Duration:
return log.Int64Value(val.Nanoseconds())
case complex64:
r := log.Float64("r", real(complex128(val)))
i := log.Float64("i", imag(complex128(val)))
return log.MapValue(r, i)
case complex128:
r := log.Float64("r", real(val))
i := log.Float64("i", imag(val))
return log.MapValue(r, i)
case time.Time:
return log.Int64Value(val.UnixNano())
case []byte:
return log.BytesValue(val)
case error:
return log.StringValue(val.Error())
}

t := reflect.TypeOf(v)
if t == nil {
return log.Value{}
}
val := reflect.ValueOf(v)
switch t.Kind() {
case reflect.Struct:
return log.StringValue(fmt.Sprintf("%+v", v))
case reflect.Slice, reflect.Array:
items := make([]log.Value, 0, val.Len())
for i := 0; i < val.Len(); i++ {
items = append(items, convertValue(val.Index(i).Interface()))
}
return log.SliceValue(items...)
case reflect.Map:
kvs := make([]log.KeyValue, 0, val.Len())
for _, k := range val.MapKeys() {
var key string
switch k.Kind() {
case reflect.String:
key = k.String()
default:
key = fmt.Sprintf("%+v", k.Interface())
}
kvs = append(kvs, log.KeyValue{
Key: key,
Value: convertValue(val.MapIndex(k).Interface()),
})
}
return log.MapValue(kvs...)
case reflect.Ptr, reflect.Interface:
if val.IsNil() {
return log.Value{}
}
return convertValue(val.Elem().Interface())
}

// Try to handle this as gracefully as possible.
//
// Don't panic here. it is preferable to have user's open issue
// asking why their attributes have a "unhandled: " prefix than
// say that their code is panicking.
return log.StringValue(fmt.Sprintf("unhandled: (%s) %+v", t, v))
}

// convertUintValue converts a uint64 to a log.Value.
// If the value is too large to fit in an int64, it is converted to a string.
func convertUintValue(v uint64) log.Value {
if v > math.MaxInt64 {
return log.StringValue(strconv.FormatUint(v, 10))
}
return log.Int64Value(int64(v))
}
Loading

0 comments on commit 21bc6b7

Please sign in to comment.