id.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package telemetry // import "go.opentelemetry.io/otel/trace/internal/telemetry"
  4. import (
  5. "encoding/hex"
  6. "errors"
  7. "fmt"
  8. )
  9. const (
  10. traceIDSize = 16
  11. spanIDSize = 8
  12. )
  13. // TraceID is a custom data type that is used for all trace IDs.
  14. type TraceID [traceIDSize]byte
  15. // String returns the hex string representation form of a TraceID.
  16. func (tid TraceID) String() string {
  17. return hex.EncodeToString(tid[:])
  18. }
  19. // IsEmpty returns false if id contains at least one non-zero byte.
  20. func (tid TraceID) IsEmpty() bool {
  21. return tid == [traceIDSize]byte{}
  22. }
  23. // MarshalJSON converts the trace ID into a hex string enclosed in quotes.
  24. func (tid TraceID) MarshalJSON() ([]byte, error) {
  25. if tid.IsEmpty() {
  26. return []byte(`""`), nil
  27. }
  28. return marshalJSON(tid[:])
  29. }
  30. // UnmarshalJSON inflates the trace ID from hex string, possibly enclosed in
  31. // quotes.
  32. func (tid *TraceID) UnmarshalJSON(data []byte) error {
  33. *tid = [traceIDSize]byte{}
  34. return unmarshalJSON(tid[:], data)
  35. }
  36. // SpanID is a custom data type that is used for all span IDs.
  37. type SpanID [spanIDSize]byte
  38. // String returns the hex string representation form of a SpanID.
  39. func (sid SpanID) String() string {
  40. return hex.EncodeToString(sid[:])
  41. }
  42. // IsEmpty returns true if the span ID contains at least one non-zero byte.
  43. func (sid SpanID) IsEmpty() bool {
  44. return sid == [spanIDSize]byte{}
  45. }
  46. // MarshalJSON converts span ID into a hex string enclosed in quotes.
  47. func (sid SpanID) MarshalJSON() ([]byte, error) {
  48. if sid.IsEmpty() {
  49. return []byte(`""`), nil
  50. }
  51. return marshalJSON(sid[:])
  52. }
  53. // UnmarshalJSON decodes span ID from hex string, possibly enclosed in quotes.
  54. func (sid *SpanID) UnmarshalJSON(data []byte) error {
  55. *sid = [spanIDSize]byte{}
  56. return unmarshalJSON(sid[:], data)
  57. }
  58. // marshalJSON converts id into a hex string enclosed in quotes.
  59. func marshalJSON(id []byte) ([]byte, error) {
  60. // Plus 2 quote chars at the start and end.
  61. hexLen := hex.EncodedLen(len(id)) + 2
  62. b := make([]byte, hexLen)
  63. hex.Encode(b[1:hexLen-1], id)
  64. b[0], b[hexLen-1] = '"', '"'
  65. return b, nil
  66. }
  67. // unmarshalJSON inflates trace id from hex string, possibly enclosed in quotes.
  68. func unmarshalJSON(dst []byte, src []byte) error {
  69. if l := len(src); l >= 2 && src[0] == '"' && src[l-1] == '"' {
  70. src = src[1 : l-1]
  71. }
  72. nLen := len(src)
  73. if nLen == 0 {
  74. return nil
  75. }
  76. if len(dst) != hex.DecodedLen(nLen) {
  77. return errors.New("invalid length for ID")
  78. }
  79. _, err := hex.Decode(dst, src)
  80. if err != nil {
  81. return fmt.Errorf("cannot unmarshal ID from string '%s': %w", string(src), err)
  82. }
  83. return nil
  84. }