Skip to content

Commit

Permalink
log: Add String method to Value and KeyValue (open-telemetry#5117)
Browse files Browse the repository at this point in the history
  • Loading branch information
pellared committed Apr 2, 2024
1 parent b7fdeb9 commit e6e44de
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add support for `Summary` metrics in the `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` exporters. (#5100)
- Add `otel.scope.name` and `otel.scope.version` tags to spans exported by `go.opentelemetry.io/otel/exporters/zipkin`. (#5108)
- Add support for `AddLink` to `go.opentelemetry.io/otel/bridge/opencensus`. (#5116)
- Add `String` method to `Value` and `KeyValue` in `go.opentelemetry.io/otel/log`. (#5117)

### Changed

Expand Down
43 changes: 43 additions & 0 deletions log/keyvalue.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ package log // import "go.opentelemetry.io/otel/log"
import (
"bytes"
"errors"
"fmt"
"math"
"slices"
"strconv"
"unsafe"

"go.opentelemetry.io/otel/internal/global"
Expand Down Expand Up @@ -265,6 +267,39 @@ func (v Value) Equal(w Value) bool {
}
}

// String returns Value's value as a string, formatted like [fmt.Sprint].
//
// The returned string is meant for debugging;
// the string representation is not stable.
func (v Value) String() string {
switch v.Kind() {
case KindString:
return v.asString()
case KindInt64:
return strconv.FormatInt(int64(v.num), 10)
case KindFloat64:
return strconv.FormatFloat(v.asFloat64(), 'g', -1, 64)
case KindBool:
return strconv.FormatBool(v.asBool())
case KindBytes:
return fmt.Sprint(v.asBytes())
case KindMap:
return fmt.Sprint(v.asMap())
case KindSlice:
return fmt.Sprint(v.asSlice())
case KindEmpty:
return "<nil>"
default:
// Try to handle this as gracefully as possible.
//
// Don't panic here. The goal here is to have developers find this
// first if a slog.Kind is is not handled. 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 fmt.Sprintf("<unhandled log.Kind: %s>", v.Kind())
}
}

// A KeyValue is a key-value pair used to represent a log attribute (a
// superset of [go.opentelemetry.io/otel/attribute.KeyValue]) and map item.
type KeyValue struct {
Expand Down Expand Up @@ -321,3 +356,11 @@ func Map(key string, value ...KeyValue) KeyValue {
func Empty(key string) KeyValue {
return KeyValue{key, Value{}}
}

// String returns key-value pair as a string, formatted like "key:value".
//
// The returned string is meant for debugging;
// the string representation is not stable.
func (a KeyValue) String() string {
return fmt.Sprintf("%s:%s", a.Key, a.Value)
}
19 changes: 19 additions & 0 deletions log/keyvalue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,25 @@ func TestEmpty(t *testing.T) {
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestValueString(t *testing.T) {
for _, test := range []struct {
v log.Value
want string
}{
{log.Int64Value(-3), "-3"},
{log.Float64Value(.15), "0.15"},
{log.BoolValue(true), "true"},
{log.StringValue("foo"), "foo"},
{log.BytesValue([]byte{2, 4, 6}), "[2 4 6]"},
{log.SliceValue(log.IntValue(3), log.StringValue("foo")), "[3 foo]"},
{log.MapValue(log.Int("a", 1), log.Bool("b", true)), "[a:1 b:true]"},
{log.Value{}, "<nil>"},
} {
got := test.v.String()
assert.Equal(t, test.want, got)
}
}

type logSink struct {
logr.LogSink

Expand Down

0 comments on commit e6e44de

Please sign in to comment.