Просмотр исходного кода

Fixed #TASK_GK-2944 trace add otel

Carl 2 лет назад
Родитель
Сommit
89db04099d
100 измененных файлов с 15911 добавлено и 0 удалено
  1. 5 0
      go.mod
  2. 5 0
      pkg/go.opentelemetry.io/otel/.codespellignore
  3. 10 0
      pkg/go.opentelemetry.io/otel/.codespellrc
  4. 3 0
      pkg/go.opentelemetry.io/otel/.gitattributes
  5. 29 0
      pkg/go.opentelemetry.io/otel/.github/ISSUE_TEMPLATE/bug_report.md
  6. 29 0
      pkg/go.opentelemetry.io/otel/.github/ISSUE_TEMPLATE/feature_request.md
  7. 22 0
      pkg/go.opentelemetry.io/otel/.github/ISSUE_TEMPLATE/version_release.md
  8. 21 0
      pkg/go.opentelemetry.io/otel/.github/codecov.yaml
  9. 300 0
      pkg/go.opentelemetry.io/otel/.github/dependabot.yml
  10. 33 0
      pkg/go.opentelemetry.io/otel/.github/workflows/benchmark.yml
  11. 34 0
      pkg/go.opentelemetry.io/otel/.github/workflows/changelog.yml
  12. 139 0
      pkg/go.opentelemetry.io/otel/.github/workflows/ci.yml
  13. 39 0
      pkg/go.opentelemetry.io/otel/.github/workflows/codeql-analysis.yml
  14. 14 0
      pkg/go.opentelemetry.io/otel/.github/workflows/codespell.yaml
  15. 23 0
      pkg/go.opentelemetry.io/otel/.github/workflows/create-dependabot-pr.yml
  16. 28 0
      pkg/go.opentelemetry.io/otel/.github/workflows/dependabot.yml
  17. 27 0
      pkg/go.opentelemetry.io/otel/.github/workflows/gosec.yml
  18. 16 0
      pkg/go.opentelemetry.io/otel/.github/workflows/links-fail-fast.yml
  19. 27 0
      pkg/go.opentelemetry.io/otel/.github/workflows/links.yml
  20. 34 0
      pkg/go.opentelemetry.io/otel/.github/workflows/markdown-fail-fast.yml
  21. 31 0
      pkg/go.opentelemetry.io/otel/.github/workflows/markdown.yml
  22. 65 0
      pkg/go.opentelemetry.io/otel/.github/workflows/scripts/dependabot-pr.sh
  23. 25 0
      pkg/go.opentelemetry.io/otel/.gitignore
  24. 3 0
      pkg/go.opentelemetry.io/otel/.gitmodules
  25. 281 0
      pkg/go.opentelemetry.io/otel/.golangci.yml
  26. 6 0
      pkg/go.opentelemetry.io/otel/.lycheeignore
  27. 29 0
      pkg/go.opentelemetry.io/otel/.markdownlint.yaml
  28. 2737 0
      pkg/go.opentelemetry.io/otel/CHANGELOG.md
  29. 17 0
      pkg/go.opentelemetry.io/otel/CODEOWNERS
  30. 620 0
      pkg/go.opentelemetry.io/otel/CONTRIBUTING.md
  31. 201 0
      pkg/go.opentelemetry.io/otel/LICENSE
  32. 291 0
      pkg/go.opentelemetry.io/otel/Makefile
  33. 111 0
      pkg/go.opentelemetry.io/otel/README.md
  34. 139 0
      pkg/go.opentelemetry.io/otel/RELEASING.md
  35. 224 0
      pkg/go.opentelemetry.io/otel/VERSIONING.md
  36. 284 0
      pkg/go.opentelemetry.io/otel/attribute/benchmark_test.go
  37. 16 0
      pkg/go.opentelemetry.io/otel/attribute/doc.go
  38. 146 0
      pkg/go.opentelemetry.io/otel/attribute/encoder.go
  39. 60 0
      pkg/go.opentelemetry.io/otel/attribute/filter.go
  40. 87 0
      pkg/go.opentelemetry.io/otel/attribute/filter_test.go
  41. 161 0
      pkg/go.opentelemetry.io/otel/attribute/iterator.go
  42. 148 0
      pkg/go.opentelemetry.io/otel/attribute/iterator_test.go
  43. 134 0
      pkg/go.opentelemetry.io/otel/attribute/key.go
  44. 101 0
      pkg/go.opentelemetry.io/otel/attribute/key_test.go
  45. 86 0
      pkg/go.opentelemetry.io/otel/attribute/kv.go
  46. 182 0
      pkg/go.opentelemetry.io/otel/attribute/kv_test.go
  47. 429 0
      pkg/go.opentelemetry.io/otel/attribute/set.go
  48. 227 0
      pkg/go.opentelemetry.io/otel/attribute/set_test.go
  49. 31 0
      pkg/go.opentelemetry.io/otel/attribute/type_string.go
  50. 270 0
      pkg/go.opentelemetry.io/otel/attribute/value.go
  51. 186 0
      pkg/go.opentelemetry.io/otel/attribute/value_test.go
  52. 552 0
      pkg/go.opentelemetry.io/otel/baggage/baggage.go
  53. 844 0
      pkg/go.opentelemetry.io/otel/baggage/baggage_test.go
  54. 39 0
      pkg/go.opentelemetry.io/otel/baggage/context.go
  55. 36 0
      pkg/go.opentelemetry.io/otel/baggage/context_test.go
  56. 20 0
      pkg/go.opentelemetry.io/otel/baggage/doc.go
  57. 63 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/doc.go
  58. 44 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/example_test.go
  59. 35 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/go.mod
  60. 113 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/go.sum
  61. 21 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/handler.go
  62. 47 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/attributes.go
  63. 56 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/attributes_test.go
  64. 33 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/span_context.go
  65. 80 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/span_context_test.go
  66. 46 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/tracer_start_options.go
  67. 52 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/tracer_start_options_test.go
  68. 202 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric/metric.go
  69. 634 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric/metric_test.go
  70. 34 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc/span_context.go
  71. 67 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc/span_context_test.go
  72. 131 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/span.go
  73. 268 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/span_test.go
  74. 69 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/tracer.go
  75. 161 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/tracer_test.go
  76. 59 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/metric.go
  77. 159 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/metric_test.go
  78. 289 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/test/bridge_test.go
  79. 32 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/test/go.mod
  80. 105 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/test/go.sum
  81. 44 0
      pkg/go.opentelemetry.io/otel/bridge/opencensus/trace.go
  82. 64 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/README.md
  83. 844 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/bridge.go
  84. 578 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/bridge_test.go
  85. 105 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/doc.go
  86. 25 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/go.mod
  87. 21 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/go.sum
  88. 15 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/internal/doc.go
  89. 294 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/internal/mock.go
  90. 76 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/migration/api.go
  91. 39 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/migration/defer.go
  92. 727 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/mix_test.go
  93. 71 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/provider.go
  94. 85 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/provider_test.go
  95. 99 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/test/bridge_grpc_test.go
  96. 36 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/test/go.mod
  97. 68 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/test/go.sum
  98. 43 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/util.go
  99. 104 0
      pkg/go.opentelemetry.io/otel/bridge/opentracing/wrapper.go
  100. 116 0
      pkg/go.opentelemetry.io/otel/codes/codes.go

+ 5 - 0
go.mod

@@ -187,4 +187,9 @@ require (
 replace (
 	github.com/optiopay/kafka => github.com/cilium/kafka v0.0.0-20180809090225-01ce283b732b
 	github.com/pyroscope-io/dotnetdiag => github.com/coroot/dotnetdiag v1.2.2
+	go.opentelemetry.io/otel => ./pkg/go.opentelemetry.io/otel
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp => ./pkg/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace => ./pkg/go.opentelemetry.io/otel/exporters/otlp/otlptrace
+	go.opentelemetry.io/otel/sdk => ./pkg/go.opentelemetry.io/otel/sdk
+	go.opentelemetry.io/otel/trace => ./pkg/go.opentelemetry.io/otel/trace
 )

+ 5 - 0
pkg/go.opentelemetry.io/otel/.codespellignore

@@ -0,0 +1,5 @@
+ot
+fo
+te
+collison
+consequentially

+ 10 - 0
pkg/go.opentelemetry.io/otel/.codespellrc

@@ -0,0 +1,10 @@
+# https://github.com/codespell-project/codespell
+[codespell]
+builtin = clear,rare,informal
+check-filenames =
+check-hidden =
+ignore-words = .codespellignore
+interactive = 1
+skip = .git,go.mod,go.sum,semconv,venv,.tools
+uri-ignore-words-list = *
+write =

+ 3 - 0
pkg/go.opentelemetry.io/otel/.gitattributes

@@ -0,0 +1,3 @@
+* text=auto eol=lf
+*.{cmd,[cC][mM][dD]} text eol=crlf
+*.{bat,[bB][aA][tT]} text eol=crlf

+ 29 - 0
pkg/go.opentelemetry.io/otel/.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,29 @@
+---
+name: Bug report
+about: Create a report of invalid behavior to help us improve
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+### Description
+
+A clear and concise description of what the bug is.
+
+### Environment
+
+- OS: [e.g. iOS]
+- Architecture: [e.g. x86, i386]
+- Go Version: [e.g. 1.15]
+- opentelemetry-go version: [e.g. v0.14.0, 3c7face]
+
+### Steps To Reproduce
+
+1. Use the configuration '...'
+2. Run '...'
+3. See error
+
+### Expected behavior
+
+A clear and concise description of what you expected to happen.

+ 29 - 0
pkg/go.opentelemetry.io/otel/.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,29 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+### Problem Statement
+
+A clear and concise description of what the problem is.
+Ex. I'm always frustrated when [...]
+
+### Proposed Solution
+
+A clear and concise description of what you want to happen.
+
+#### Alternatives
+
+A clear and concise description of any alternative solutions or features you've considered.
+
+#### Prior Art
+
+A clear and concise list of any similar and existing solutions from other projects that provide context to possible solutions.
+
+### Additional Context
+
+Add any other context or screenshots about the feature request here.

+ 22 - 0
pkg/go.opentelemetry.io/otel/.github/ISSUE_TEMPLATE/version_release.md

@@ -0,0 +1,22 @@
+---
+name: Version Release
+about: Checklist to follow when shipping a new release.
+title: 'Release <V1.x.x> Checklist'
+labels: ''
+assignees: ''
+
+---
+
+<!-- markdownlint-disable MD034 -->
+<!--- The current milestones can be found at https://github.com/open-telemetry/opentelemetry-go/milestones -->
+- [ ] Complete [Milestone](https://github.com/open-telemetry/opentelemetry-go/milestone/<Release Milesone>)
+<!-- markdownlint-enable MD034 -->
+- [ ] Update contrib codebase to support changes about to be released (use a git sha version)
+- [ ] [Pre-release](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#pre-release)
+- [ ] [Tag](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#tag)
+- [ ] [Release](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#release)
+- [ ] [Check examples](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#verify-examples)
+- [ ] [Sync with Contrib](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/RELEASING.md#upgrade-goopentelemetryiootel-packages)
+- [ ] [Release contrib](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/RELEASING.md#release-process)
+- [ ] [Sync website docs](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#website-documentation)
+- [ ] Close the milestone

+ 21 - 0
pkg/go.opentelemetry.io/otel/.github/codecov.yaml

@@ -0,0 +1,21 @@
+codecov:
+  require_ci_to_pass: yes
+
+ignore:
+  - "exporters/jaeger/internal/gen-go/**/*"
+  - "exporters/jaeger/internal/third_party/**/*"
+
+coverage:
+  precision: 1
+  round: down
+  range: "70...100"
+  status:
+    project:
+      default:
+        target: auto
+        threshold: 0.5%
+
+comment:
+  layout: "reach,diff,flags,tree"
+  behavior: default
+  require_changes: yes

+ 300 - 0
pkg/go.opentelemetry.io/otel/.github/dependabot.yml

@@ -0,0 +1,300 @@
+# File generated by dbotconf; DO NOT EDIT.
+version: 2
+updates:
+  - package-ecosystem: github-actions
+    directory: /
+    labels:
+      - dependencies
+      - actions
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: docker
+    directory: /example/zipkin
+    labels:
+      - dependencies
+      - docker
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /bridge/opencensus
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /bridge/opencensus/test
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /bridge/opentracing
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /bridge/opentracing/test
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/dice
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/fib
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/namedtracer
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/opencensus
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/otel-collector
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/passthrough
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/prometheus
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/view
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /example/zipkin
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/otlp/otlpmetric
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/otlp/otlpmetric/otlpmetricgrpc
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/otlp/otlpmetric/otlpmetrichttp
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/otlp/otlptrace
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/otlp/otlptrace/otlptracegrpc
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/otlp/otlptrace/otlptracehttp
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/prometheus
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/stdout/stdoutmetric
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/stdout/stdouttrace
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /exporters/zipkin
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /internal/tools
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /metric
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /schema
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /sdk
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /sdk/metric
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: gomod
+    directory: /trace
+    labels:
+      - dependencies
+      - go
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday
+  - package-ecosystem: pip
+    directory: /
+    labels:
+      - dependencies
+      - python
+      - Skip Changelog
+    schedule:
+      interval: weekly
+      day: sunday

+ 33 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/benchmark.yml

@@ -0,0 +1,33 @@
+name: Benchmark
+on:
+  push:
+    branches:
+      - main
+env:
+  DEFAULT_GO_VERSION: "~1.21.1"
+jobs:
+  benchmark:
+    name: Benchmarks
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-go@v4
+        with:
+          go-version: ${{ env.DEFAULT_GO_VERSION }}
+      - name: Run benchmarks
+        run: make test-bench | tee output.txt
+      - name: Download previous benchmark data
+        uses: actions/cache@v3
+        with:
+          path: ./benchmarks
+          key: ${{ runner.os }}-benchmark
+      - name: Store benchmarks result
+        uses: benchmark-action/[email protected]
+        with:
+          name: Benchmarks
+          tool: 'go'
+          output-file-path: output.txt
+          external-data-json-path: ./benchmarks/data.json
+          auto-push: false
+          fail-on-alert: false
+          alert-threshold: "400%"

+ 34 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/changelog.yml

@@ -0,0 +1,34 @@
+# This action requires that any PR targeting the main branch should touch at
+# least one CHANGELOG file. If a CHANGELOG entry is not required, or if
+# performing maintenance on the Changelog, add either \"[chore]\" to the title of
+# the pull request or add the \"Skip Changelog\" label to disable this action.
+
+name: changelog
+
+on:
+  pull_request:
+    types: [opened, synchronize, reopened, labeled, unlabeled]
+    branches:
+      - main
+jobs:
+  changelog:
+    runs-on: ubuntu-latest
+    if: ${{ !contains(github.event.pull_request.labels.*.name, 'dependencies') && !contains(github.event.pull_request.labels.*.name, 'Skip Changelog') && !contains(github.event.pull_request.title, '[chore]')}}
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Check for CHANGELOG changes
+        run: |
+          # Only the latest commit of the feature branch is available
+          # automatically. To diff with the base branch, we need to
+          # fetch that too (and we only need its latest commit).
+          git fetch origin ${{ github.base_ref }} --depth=1
+          if [[ $(git diff --name-only FETCH_HEAD | grep CHANGELOG) ]]
+          then
+            echo "A CHANGELOG was modified. Looks good!"
+          else
+            echo "No CHANGELOG was modified."
+            echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required."
+            false
+          fi

+ 139 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/ci.yml

@@ -0,0 +1,139 @@
+name: ci
+on:
+  push:
+    branches:
+      - main
+  pull_request:
+env:
+  # Path to where test results will be saved.
+  TEST_RESULTS: /tmp/test-results
+  # Default version of Go to use by CI workflows. This should be the latest
+  # release of Go; developers likely use the latest release in development and
+  # we want to catch any bugs (e.g. lint errors, race detection) with this
+  # release before they are merged. The Go compatibility guarantees ensure
+  # backwards compatibility with the previous two minor releases and we
+  # explicitly test our code for these versions so keeping this at prior
+  # versions does not add value.
+  DEFAULT_GO_VERSION: "~1.21.1"
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@v4
+      - name: Setup Environment
+        run: |
+          echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
+          echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
+      - name: Install Go
+        uses: actions/setup-go@v4
+        with:
+          go-version: ${{ env.DEFAULT_GO_VERSION }}
+          cache-dependency-path: "**/go.sum"
+      - name: Tools cache
+        uses: actions/cache@v3
+        env:
+          cache-name: go-tools-cache
+        with:
+          path: ~/.tools
+          key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('./internal/tools/**') }}
+      - name: Generate
+        run: make generate
+      - name: Run linters
+        run: make dependabot-check license-check lint vanity-import-check
+      - name: Build
+        run: make build
+      - name: Check clean repository
+        run: make check-clean-work-tree
+
+  test-race:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@v4
+      - name: Setup Environment
+        run: |
+          echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
+          echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
+      - name: Install Go
+        uses: actions/setup-go@v4
+        with:
+          go-version: ${{ env.DEFAULT_GO_VERSION }}
+          cache-dependency-path: "**/go.sum"
+      - name: Run tests with race detector
+        run: make test-race
+
+  test-coverage:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@v4
+      - name: Setup Environment
+        run: |
+          echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
+          echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
+      - name: Install Go
+        uses: actions/setup-go@v4
+        with:
+          go-version: ${{ env.DEFAULT_GO_VERSION }}
+          cache-dependency-path: "**/go.sum"
+      - name: Run coverage tests
+        run: |
+          make test-coverage
+          mkdir $TEST_RESULTS
+          cp coverage.out $TEST_RESULTS
+          cp coverage.txt $TEST_RESULTS
+          cp coverage.html $TEST_RESULTS
+      - name: Upload coverage report
+        uses: codecov/[email protected]
+        with:
+          file: ./coverage.txt
+          fail_ci_if_error: true
+          verbose: true
+      - name: Store coverage test output
+        uses: actions/upload-artifact@v3
+        with:
+          name: opentelemetry-go-test-output
+          path: ${{ env.TEST_RESULTS }}
+
+  compatibility-test:
+    strategy:
+      matrix:
+        go-version: ["~1.21.1", "~1.20.8"]
+        os: [ubuntu-latest, macos-latest, windows-latest]
+        # GitHub Actions does not support arm* architectures on default
+        # runners. It is possible to accomplish this with a self-hosted runner
+        # if we want to add this in the future:
+        # https://docs.github.com/en/actions/hosting-your-own-runners/using-self-hosted-runners-in-a-workflow
+        arch: ["386", amd64]
+        exclude:
+          # Not a supported Go OS/architecture.
+          - os: macos-latest
+            arch: "386"
+    runs-on: ${{ matrix.os }}
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+      - name: Setup Environment
+        run: |
+          echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
+          echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
+        shell: bash
+      - name: Install Go
+        uses: actions/setup-go@v4
+        with:
+          go-version: ${{ matrix.go-version }}
+          cache-dependency-path: "**/go.sum"
+      - name: Run tests
+        env:
+          GOARCH: ${{ matrix.arch }}
+        run: make test-short
+
+  test-compatibility:
+    runs-on: ubuntu-latest
+    needs: [compatibility-test]
+    steps:
+      - name: Test if compatibility-test passed
+        run: |
+          echo ${{ needs.compatibility-test.result }}
+          test ${{ needs.compatibility-test.result }} == "success"

+ 39 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/codeql-analysis.yml

@@ -0,0 +1,39 @@
+name: "CodeQL Analysis"
+
+on:
+  workflow_dispatch:
+  schedule:
+    #        ┌───────────── minute (0 - 59)
+    #        │  ┌───────────── hour (0 - 23)
+    #        │  │ ┌───────────── day of the month (1 - 31)
+    #        │  │ │ ┌───────────── month (1 - 12 or JAN-DEC)
+    #        │  │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
+    #        │  │ │ │ │
+    #        │  │ │ │ │
+    #        │  │ │ │ │
+    #        *  * * * *
+    - cron: '30 1 * * *'
+  push:
+    branches: [ main ]
+  pull_request:
+
+jobs:
+  CodeQL-Build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      # Initializes the CodeQL tools for scanning.
+      - name: Initialize CodeQL
+        uses: github/codeql-action/init@v2
+        with:
+          languages: go
+
+      - name: Autobuild
+        uses: github/codeql-action/autobuild@v2
+
+      - name: Perform CodeQL Analysis
+        uses: github/codeql-action/analyze@v2
+

+ 14 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/codespell.yaml

@@ -0,0 +1,14 @@
+name: codespell
+on:
+  push:
+    branches:
+      - main
+  pull_request:
+jobs:
+  codespell:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@v4
+      - name: Codespell
+        run: make codespell

+ 23 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/create-dependabot-pr.yml

@@ -0,0 +1,23 @@
+name: dependabot-pr
+
+on:
+  workflow_dispatch:
+
+jobs:
+  create-pr:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Install Go
+        uses: actions/setup-go@v4
+        with:
+          go-version: "~1.21.1"
+
+      - uses: actions/checkout@v4
+
+      - name: Install zsh
+        run: sudo apt-get update; sudo apt-get install zsh
+
+      - name: Run dependabot-pr.sh
+        run: ./.github/workflows/scripts/dependabot-pr.sh
+        env:
+          GITHUB_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}

+ 28 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/dependabot.yml

@@ -0,0 +1,28 @@
+name: Dependabot-Tidier
+on:
+  pull_request:
+    types: [ labeled ]
+
+jobs:
+  mod_tidier:
+    if: ${{ contains(github.event.pull_request.labels.*.name, 'dependencies') }}
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        ref: ${{ github.head_ref }}
+    - uses: actions/setup-go@v4
+      with:
+        go-version: '^1.21.1'
+    - uses: evantorrie/mott-the-tidier@v1-beta
+      id: modtidy
+      with:
+        gomods: '**/go.mod'
+        gomodsum_only: true
+    - uses: stefanzweifel/git-auto-commit-action@v4
+      id: autocommit
+      with:
+        commit_message: Auto-fix go.sum changes in dependent modules
+    - name: changes
+      run: |
+        echo "Changes detected: ${{ steps.autocommit.outputs.changes_detected }}"

+ 27 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/gosec.yml

@@ -0,0 +1,27 @@
+name: Run Gosec
+on:
+  workflow_dispatch:
+  schedule:
+    #        ┌───────────── minute (0 - 59)
+    #        │  ┌───────────── hour (0 - 23)
+    #        │  │ ┌───────────── day of the month (1 - 31)
+    #        │  │ │ ┌───────────── month (1 - 12 or JAN-DEC)
+    #        │  │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
+    #        │  │ │ │ │
+    #        │  │ │ │ │
+    #        │  │ │ │ │
+    #        *  * * * *
+    - cron: '30 2 * * *'
+jobs:
+  tests:
+    runs-on: ubuntu-latest
+    env:
+      GO111MODULE: on
+    steps:
+      - name: Checkout Source
+        uses: actions/checkout@v4
+      - name: Run Gosec Security Scanner
+        uses: securego/gosec@master
+        with:
+          args: ./...
+

+ 16 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/links-fail-fast.yml

@@ -0,0 +1,16 @@
+name: Links (Fail Fast)
+
+on:
+  push:
+  pull_request:
+
+jobs:
+  check-links:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Link Checker
+        uses: lycheeverse/[email protected]
+        with:
+          fail: true

+ 27 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/links.yml

@@ -0,0 +1,27 @@
+name: Links
+
+on:
+  repository_dispatch:
+  workflow_dispatch:
+  schedule:
+  # Everyday at 9:00 AM.
+  - cron: "0 9 * * *"
+
+jobs:
+  check-links:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout Repo
+      uses: actions/checkout@v4
+
+    - name: Link Checker
+      id: lychee
+      uses: lycheeverse/[email protected]
+
+    - name: Create Issue From File
+      if: steps.lychee.outputs.exit_code != 0
+      uses: peter-evans/create-issue-from-file@v4
+      with:
+        title: Link Checker Report
+        content-filepath: ./lychee/out.md
+        labels: report, bot-generated

+ 34 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/markdown-fail-fast.yml

@@ -0,0 +1,34 @@
+name: Markdown (Fail Fast)
+
+on:
+  push:
+  pull_request:
+
+jobs:
+  changedfiles:
+    name: changed files
+    runs-on: ubuntu-latest
+    outputs:
+      md: ${{ steps.changes.outputs.md }}
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+      - name: Get changed files
+        id: changes
+        run: |
+          echo "md=$(git diff --name-only --diff-filter=ACMRTUXB origin/${{ github.event.pull_request.base.ref }} ${{ github.event.pull_request.head.sha }} | grep .md$ | xargs)" >> $GITHUB_OUTPUT
+
+  lint:
+    name: lint markdown files
+    runs-on: ubuntu-latest
+    needs: changedfiles
+    if: ${{needs.changedfiles.outputs.md}}
+    steps:
+    - name: Checkout Repo
+      uses: actions/checkout@v4
+    - name: Run linter
+      uses: docker://avtodev/markdown-lint:v1
+      with:
+        args: ${{needs.changedfiles.outputs.md}}

+ 31 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/markdown.yml

@@ -0,0 +1,31 @@
+name: Markdown
+
+on:
+  repository_dispatch:
+  workflow_dispatch:
+  schedule:
+  # Everyday at 9:00 AM.
+  - cron: "0 9 * * *"
+
+jobs:
+  lint-markdown:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout Repo
+      uses: actions/checkout@v4
+
+    - name: Run linter
+      id: markdownlint
+      uses: docker://avtodev/markdown-lint:v1
+      with:
+        config: .markdownlint.yaml
+        args: '**/*.md'
+        output: ./markdownlint.txt
+
+    - name: Create Issue From File
+      if: steps.markdownlint.outputs.exit_code != 0
+      uses: peter-evans/create-issue-from-file@v4
+      with:
+        title: Markdown Lint Report
+        content-filepath: ./markdownlint.txt
+        labels: report, bot-generated

+ 65 - 0
pkg/go.opentelemetry.io/otel/.github/workflows/scripts/dependabot-pr.sh

@@ -0,0 +1,65 @@
+#!/bin/zsh -ex
+
+# Copyright The OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+git config user.name opentelemetrybot
+git config user.email [email protected]
+
+BRANCH=dependabot/dependabot-prs/`date +'%Y-%m-%dT%H%M%S'`
+git checkout -b $BRANCH
+
+IFS=$'\n'
+requests=($( gh pr list --search "author:app/dependabot" --json title --jq '.[].title' ))
+message=""
+dirs=(`find . -type f -name "go.mod" -exec dirname {} \; | sort | egrep  '^./'`)
+
+declare -A mods
+
+for line in $requests; do
+    echo $line
+    if [[ $line != Bump* ]]; then
+        continue
+    fi
+
+    module=$(echo $line | cut -f 2 -d " ")
+    if [[ $module == go.opentelemetry.io/otel* ]]; then
+        continue
+    fi
+    version=$(echo $line | cut -f 6 -d " ")
+
+    mods[$module]=$version
+    message+=$line
+    message+=$'\n'
+done
+
+for module version in ${(kv)mods}; do
+    topdir=`pwd`
+    for dir in $dirs; do
+        echo "checking $dir"
+        cd $dir && if grep -q "$module " go.mod; then go get "$module"@v"$version"; fi
+        cd $topdir
+    done
+done
+
+make go-mod-tidy
+make build
+
+git add go.sum go.mod
+git add "**/go.sum" "**/go.mod"
+git commit -m "dependabot updates `date`
+$message"
+git push origin $BRANCH
+
+gh pr create --title "[chore] dependabot updates `date`" --body "$message"

+ 25 - 0
pkg/go.opentelemetry.io/otel/.gitignore

@@ -0,0 +1,25 @@
+.DS_Store
+Thumbs.db
+
+.tools/
+venv/
+.idea/
+.vscode/
+*.iml
+*.so
+coverage.*
+go.work
+go.work.sum
+
+gen/
+
+/example/dice/dice
+/example/fib/fib
+/example/fib/traces.txt
+/example/jaeger/jaeger
+/example/namedtracer/namedtracer
+/example/opencensus/opencensus
+/example/passthrough/passthrough
+/example/prometheus/prometheus
+/example/zipkin/zipkin
+/example/otel-collector/otel-collector

+ 3 - 0
pkg/go.opentelemetry.io/otel/.gitmodules

@@ -0,0 +1,3 @@
+[submodule "opentelemetry-proto"]
+	path = exporters/otlp/internal/opentelemetry-proto
+	url = https://github.com/open-telemetry/opentelemetry-proto

+ 281 - 0
pkg/go.opentelemetry.io/otel/.golangci.yml

@@ -0,0 +1,281 @@
+# See https://github.com/golangci/golangci-lint#config-file
+run:
+  issues-exit-code: 1 #Default
+  tests: true #Default
+
+linters:
+  # Disable everything by default so upgrades to not include new "default
+  # enabled" linters.
+  disable-all: true
+  # Specifically enable linters we want to use.
+  enable:
+    - depguard
+    - errcheck
+    - godot
+    - gofmt
+    - goimports
+    - gosimple
+    - govet
+    - ineffassign
+    - misspell
+    - revive
+    - staticcheck
+    - typecheck
+    - unused
+
+issues:
+  # Maximum issues count per one linter.
+  # Set to 0 to disable.
+  # Default: 50
+  # Setting to unlimited so the linter only is run once to debug all issues.
+  max-issues-per-linter: 0
+  # Maximum count of issues with the same text.
+  # Set to 0 to disable.
+  # Default: 3
+  # Setting to unlimited so the linter only is run once to debug all issues.
+  max-same-issues: 0
+  # Excluding configuration per-path, per-linter, per-text and per-source.
+  exclude-rules:
+    # TODO: Having appropriate comments for exported objects helps development,
+    # even for objects in internal packages. Appropriate comments for all
+    # exported objects should be added and this exclusion removed.
+    - path: '.*internal/.*'
+      text: "exported (method|function|type|const) (.+) should have comment or be unexported"
+      linters:
+        - revive
+    # Yes, they are, but it's okay in a test.
+    - path: _test\.go
+      text: "exported func.*returns unexported type.*which can be annoying to use"
+      linters:
+        - revive
+    # Example test functions should be treated like main.
+    - path: example.*_test\.go
+      text: "calls to (.+) only in main[(][)] or init[(][)] functions"
+      linters:
+        - revive
+  include:
+    # revive exported should have comment or be unexported.
+    - EXC0012
+    # revive package comment should be of the form ...
+    - EXC0013
+
+linters-settings:
+  depguard:
+    rules:
+      non-tests:
+        files:
+          - "!$test"
+          - "!**/*test/*.go"
+          - "!**/internal/matchers/*.go"
+        deny:
+          - pkg: "testing"
+          - pkg: "github.com/stretchr/testify"
+          - pkg: "crypto/md5"
+          - pkg: "crypto/sha1"
+          - pkg: "crypto/**/pkix"
+      otlp-internal:
+        files:
+          - "!**/exporters/otlp/internal/**/*.go"
+        deny:
+          - pkg: "go.opentelemetry.io/otel/exporters/otlp/internal"
+            desc: Do not use cross-module internal packages.
+      otlptrace-internal:
+        files:
+          - "!**/exporters/otlp/otlptrace/*.go"
+          - "!**/exporters/otlp/otlptrace/internal/**.go"
+        deny:
+          - pkg: "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal"
+            desc: Do not use cross-module internal packages.
+      otlpmetric-internal:
+        files:
+          - "!**/exporters/otlp/otlpmetric/internal/*.go"
+          - "!**/exporters/otlp/otlpmetric/internal/**/*.go"
+        deny:
+          - pkg: "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal"
+            desc: Do not use cross-module internal packages.
+      otel-internal:
+        files:
+          - "**/sdk/*.go"
+          - "**/sdk/**/*.go"
+          - "**/exporters/*.go"
+          - "**/exporters/**/*.go"
+          - "**/schema/*.go"
+          - "**/schema/**/*.go"
+          - "**/metric/*.go"
+          - "**/metric/**/*.go"
+          - "**/bridge/*.go"
+          - "**/bridge/**/*.go"
+          - "**/example/*.go"
+          - "**/example/**/*.go"
+          - "**/trace/*.go"
+          - "**/trace/**/*.go"
+        deny:
+          - pkg: "go.opentelemetry.io/otel/internal$"
+            desc: Do not use cross-module internal packages.
+          - pkg: "go.opentelemetry.io/otel/internal/attribute"
+            desc: Do not use cross-module internal packages.
+          - pkg: "go.opentelemetry.io/otel/internal/internaltest"
+            desc: Do not use cross-module internal packages.
+          - pkg: "go.opentelemetry.io/otel/internal/matchers"
+            desc: Do not use cross-module internal packages.
+  godot:
+    exclude:
+      # Exclude links.
+      - '^ *\[[^]]+\]:'
+      # Exclude sentence fragments for lists.
+      - '^[ ]*[-•]'
+      # Exclude sentences prefixing a list.
+      - ':$'
+  goimports:
+    local-prefixes: go.opentelemetry.io
+  misspell:
+    locale: US
+    ignore-words:
+      - cancelled
+  revive:
+    # Sets the default failure confidence.
+    # This means that linting errors with less than 0.8 confidence will be ignored.
+    # Default: 0.8
+    confidence: 0.01
+    rules:
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#blank-imports
+      - name: blank-imports
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bool-literal-in-expr
+      - name: bool-literal-in-expr
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#constant-logical-expr
+      - name: constant-logical-expr
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument
+      # TODO (#3372) re-enable linter when it is compatible. https://github.com/golangci/golangci-lint/issues/3280
+      - name: context-as-argument
+        disabled: true
+        arguments:
+          allowTypesBefore: "*testing.T"
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-keys-type
+      - name: context-keys-type
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#deep-exit
+      - name: deep-exit
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#defer
+      - name: defer
+        disabled: false
+        arguments:
+          - ["call-chain", "loop"]
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#dot-imports
+      - name: dot-imports
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#duplicated-imports
+      - name: duplicated-imports
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#early-return
+      - name: early-return
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block
+      - name: empty-block
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines
+      - name: empty-lines
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-naming
+      - name: error-naming
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-return
+      - name: error-return
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-strings
+      - name: error-strings
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#errorf
+      - name: errorf
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported
+      - name: exported
+        disabled: false
+        arguments:
+          - "sayRepetitiveInsteadOfStutters"
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#flag-parameter
+      - name: flag-parameter
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#identical-branches
+      - name: identical-branches
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#if-return
+      - name: if-return
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#increment-decrement
+      - name: increment-decrement
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#indent-error-flow
+      - name: indent-error-flow
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing
+      - name: import-shadowing
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#package-comments
+      - name: package-comments
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range
+      - name: range
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-in-closure
+      - name: range-val-in-closure
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-address
+      - name: range-val-address
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redefines-builtin-id
+      - name: redefines-builtin-id
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-format
+      - name: string-format
+        disabled: false
+        arguments:
+          - - panic
+            - '/^[^\n]*$/'
+            - must not contain line breaks
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#struct-tag
+      - name: struct-tag
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#superfluous-else
+      - name: superfluous-else
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-equal
+      - name: time-equal
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-naming
+      - name: var-naming
+        disabled: false
+        arguments:
+          - ["ID"] # AllowList
+          - ["Otel", "Aws", "Gcp"] # DenyList
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-declaration
+      - name: var-declaration
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unconditional-recursion
+      - name: unconditional-recursion
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return
+      - name: unexported-return
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unhandled-error
+      - name: unhandled-error
+        disabled: false
+        arguments:
+          - "fmt.Fprint"
+          - "fmt.Fprintf"
+          - "fmt.Fprintln"
+          - "fmt.Print"
+          - "fmt.Printf"
+          - "fmt.Println"
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unnecessary-stmt
+      - name: unnecessary-stmt
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#useless-break
+      - name: useless-break
+        disabled: false
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#waitgroup-by-value
+      - name: waitgroup-by-value
+        disabled: false

+ 6 - 0
pkg/go.opentelemetry.io/otel/.lycheeignore

@@ -0,0 +1,6 @@
+http://localhost
+http://jaeger-collector
+https://github.com/open-telemetry/opentelemetry-go/milestone/
+https://github.com/open-telemetry/opentelemetry-go/projects
+file:///home/runner/work/opentelemetry-go/opentelemetry-go/libraries
+file:///home/runner/work/opentelemetry-go/opentelemetry-go/manual

+ 29 - 0
pkg/go.opentelemetry.io/otel/.markdownlint.yaml

@@ -0,0 +1,29 @@
+# Default state for all rules
+default: true
+
+# ul-style
+MD004: false
+
+# hard-tabs
+MD010: false
+
+# line-length
+MD013: false
+
+# no-duplicate-header
+MD024:
+  siblings_only: true
+
+#single-title
+MD025: false
+
+# ol-prefix
+MD029:
+  style: ordered
+
+# no-inline-html
+MD033: false
+
+# fenced-code-language
+MD040: false
+

+ 2737 - 0
pkg/go.opentelemetry.io/otel/CHANGELOG.md

@@ -0,0 +1,2737 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+
+This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [1.19.0/0.42.0/0.0.7] 2023-09-28
+
+This release contains the first stable release of the OpenTelemetry Go [metric SDK].
+Our project stability guarantees now apply to the `go.opentelemetry.io/otel/sdk/metric` package.
+See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
+
+### Added
+
+- Add the "Roll the dice" getting started application example in `go.opentelemetry.io/otel/example/dice`. (#4539)
+- The `WithWriter` and `WithPrettyPrint` options to `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` to set a custom `io.Writer`, and allow displaying the output in human-readable JSON. (#4507)
+
+### Changed
+
+- Allow '/' characters in metric instrument names. (#4501)
+- The exporter in `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` does not prettify its output by default anymore. (#4507)
+- Upgrade `gopkg.io/yaml` from `v2` to `v3` in `go.opentelemetry.io/otel/schema`. (#4535)
+
+### Fixed
+
+- In `go.opentelemetry.op/otel/exporters/prometheus`, don't try to create the Prometheus metric on every `Collect` if we know the scope is invalid. (#4499)
+
+### Removed
+
+- Remove `"go.opentelemetry.io/otel/bridge/opencensus".NewMetricExporter`, which is replaced by `NewMetricProducer`. (#4566)
+
+## [1.19.0-rc.1/0.42.0-rc.1] 2023-09-14
+
+This is a release candidate for the v1.19.0/v0.42.0 release.
+That release is expected to include the `v1` release of the OpenTelemetry Go metric SDK and will provide stability guarantees of that SDK.
+See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
+
+### Changed
+
+- Allow '/' characters in metric instrument names. (#4501)
+
+### Fixed
+
+- In `go.opentelemetry.op/otel/exporters/prometheus`, don't try to create the prometheus metric on every `Collect` if we know the scope is invalid. (#4499)
+
+## [1.18.0/0.41.0/0.0.6] 2023-09-12
+
+This release drops the compatibility guarantee of [Go 1.19].
+
+### Added
+
+- Add `WithProducer` option in `go.opentelemetry.op/otel/exporters/prometheus` to restore the ability to register producers on the prometheus exporter's manual reader. (#4473)
+- Add `IgnoreValue` option in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest` to allow ignoring values when comparing metrics. (#4447)
+
+### Changed
+
+- Use a `TestingT` interface instead of `*testing.T` struct in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#4483)
+
+### Deprecated
+
+- The `NewMetricExporter` in `go.opentelemetry.io/otel/bridge/opencensus` was deprecated in `v0.35.0` (#3541).
+  The deprecation notice format for the function has been corrected to trigger Go documentation and build tooling. (#4470)
+
+### Removed
+
+- Removed the deprecated `go.opentelemetry.io/otel/exporters/jaeger` package. (#4467)
+- Removed the deprecated `go.opentelemetry.io/otel/example/jaeger` package. (#4467)
+- Removed the deprecated `go.opentelemetry.io/otel/sdk/metric/aggregation` package. (#4468)
+- Removed the deprecated internal packages in `go.opentelemetry.io/otel/exporters/otlp` and its sub-packages. (#4469)
+- Dropped guaranteed support for versions of Go less than 1.20. (#4481)
+
+## [1.17.0/0.40.0/0.0.5] 2023-08-28
+
+### Added
+
+- Export the `ManualReader` struct in `go.opentelemetry.io/otel/sdk/metric`. (#4244)
+- Export the `PeriodicReader` struct in `go.opentelemetry.io/otel/sdk/metric`. (#4244)
+- Add support for exponential histogram aggregations.
+  A histogram can be configured as an exponential histogram using a view with `"go.opentelemetry.io/otel/sdk/metric".ExponentialHistogram` as the aggregation. (#4245)
+- Export the `Exporter` struct in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4272)
+- Export the `Exporter` struct in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4272)
+- The exporters in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` now support the `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE` environment variable. (#4287)
+- Add `WithoutCounterSuffixes` option in `go.opentelemetry.io/otel/exporters/prometheus` to disable addition of `_total` suffixes. (#4306)
+- Add info and debug logging to the metric SDK in `go.opentelemetry.io/otel/sdk/metric`. (#4315)
+- The `go.opentelemetry.io/otel/semconv/v1.21.0` package.
+  The package contains semantic conventions from the `v1.21.0` version of the OpenTelemetry Semantic Conventions. (#4362)
+- Accept 201 to 299 HTTP status as success in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#4365)
+- Document the `Temporality` and `Aggregation` methods of the `"go.opentelemetry.io/otel/sdk/metric".Exporter"` need to be concurrent safe. (#4381)
+- Expand the set of units supported by the Prometheus exporter, and don't add unit suffixes if they are already present in `go.opentelemetry.op/otel/exporters/prometheus` (#4374)
+- Move the `Aggregation` interface and its implementations from `go.opentelemetry.io/otel/sdk/metric/aggregation` to `go.opentelemetry.io/otel/sdk/metric`. (#4435)
+- The exporters in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` now support the `OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION` environment variable. (#4437)
+- Add the `NewAllowKeysFilter` and `NewDenyKeysFilter` functions to `go.opentelemetry.io/otel/attribute` to allow convenient creation of allow-keys and deny-keys filters. (#4444)
+- Support Go 1.21. (#4463)
+
+### Changed
+
+- Starting from `v1.21.0` of semantic conventions, `go.opentelemetry.io/otel/semconv/{version}/httpconv` and `go.opentelemetry.io/otel/semconv/{version}/netconv` packages will no longer be published. (#4145)
+- Log duplicate instrument conflict at a warning level instead of info in `go.opentelemetry.io/otel/sdk/metric`. (#4202)
+- Return an error on the creation of new instruments in `go.opentelemetry.io/otel/sdk/metric` if their name doesn't pass regexp validation. (#4210)
+- `NewManualReader` in `go.opentelemetry.io/otel/sdk/metric` returns `*ManualReader` instead of `Reader`. (#4244)
+- `NewPeriodicReader` in `go.opentelemetry.io/otel/sdk/metric` returns `*PeriodicReader` instead of `Reader`. (#4244)
+- Count the Collect time in the `PeriodicReader` timeout in `go.opentelemetry.io/otel/sdk/metric`. (#4221)
+- The function `New` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` returns `*Exporter` instead of `"go.opentelemetry.io/otel/sdk/metric".Exporter`. (#4272)
+- The function `New` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` returns `*Exporter` instead of `"go.opentelemetry.io/otel/sdk/metric".Exporter`. (#4272)
+- If an attribute set is omitted from an async callback, the previous value will no longer be exported in `go.opentelemetry.io/otel/sdk/metric`. (#4290)
+- If an attribute set is observed multiple times in an async callback in `go.opentelemetry.io/otel/sdk/metric`, the values will be summed instead of the last observation winning. (#4289)
+- Allow the explicit bucket histogram aggregation to be used for the up-down counter, observable counter, observable up-down counter, and observable gauge in the `go.opentelemetry.io/otel/sdk/metric` package. (#4332)
+- Restrict `Meter`s in `go.opentelemetry.io/otel/sdk/metric` to only register and collect instruments it created. (#4333)
+- `PeriodicReader.Shutdown` and `PeriodicReader.ForceFlush` in `go.opentelemetry.io/otel/sdk/metric` now apply the periodic reader's timeout to the operation if the user provided context does not contain a deadline. (#4356, #4377)
+- Upgrade all use of `go.opentelemetry.io/otel/semconv` to use `v1.21.0`. (#4408)
+- Increase instrument name maximum length from 63 to 255 characters in `go.opentelemetry.io/otel/sdk/metric`. (#4434)
+- Add `go.opentelemetry.op/otel/sdk/metric.WithProducer` as an `Option` for `"go.opentelemetry.io/otel/sdk/metric".NewManualReader` and `"go.opentelemetry.io/otel/sdk/metric".NewPeriodicReader`. (#4346)
+
+### Removed
+
+- Remove `Reader.RegisterProducer` in `go.opentelemetry.io/otel/metric`.
+  Use the added `WithProducer` option instead. (#4346)
+- Remove `Reader.ForceFlush` in `go.opentelemetry.io/otel/metric`.
+  Notice that `PeriodicReader.ForceFlush` is still available. (#4375)
+
+### Fixed
+
+- Correctly format log messages from the `go.opentelemetry.io/otel/exporters/zipkin` exporter. (#4143)
+- Log an error for calls to `NewView` in `go.opentelemetry.io/otel/sdk/metric` that have empty criteria. (#4307)
+- Fix `"go.opentelemetry.io/otel/sdk/resource".WithHostID()` to not set an empty `host.id`. (#4317)
+- Use the instrument identifying fields to cache aggregators and determine duplicate instrument registrations in `go.opentelemetry.io/otel/sdk/metric`. (#4337)
+- Detect duplicate instruments for case-insensitive names in `go.opentelemetry.io/otel/sdk/metric`. (#4338)
+- The `ManualReader` will not panic if `AggregationSelector` returns `nil` in `go.opentelemetry.io/otel/sdk/metric`. (#4350)
+- If a `Reader`'s `AggregationSelector` returns `nil` or `DefaultAggregation` the pipeline will use the default aggregation. (#4350)
+- Log a suggested view that fixes instrument conflicts in `go.opentelemetry.io/otel/sdk/metric`. (#4349)
+- Fix possible panic, deadlock and race condition in batch span processor in `go.opentelemetry.io/otel/sdk/trace`. (#4353)
+- Improve context cancellation handling in batch span processor's `ForceFlush` in  `go.opentelemetry.io/otel/sdk/trace`. (#4369)
+- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` using gotmpl. (#4397, #3846)
+- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal` using gotmpl. (#4404, #3846)
+- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal` using gotmpl. (#4407, #3846)
+- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` using gotmpl. (#4400, #3846)
+- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` using gotmpl. (#4401, #3846)
+- Do not block the metric SDK when OTLP metric exports are blocked in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#3925, #4395)
+- Do not append `_total` if the counter already has that suffix for the Prometheus exproter in `go.opentelemetry.io/otel/exporter/prometheus`. (#4373)
+- Fix resource detection data race in `go.opentelemetry.io/otel/sdk/resource`. (#4409)
+- Use the first-seen instrument name during instrument name conflicts in `go.opentelemetry.io/otel/sdk/metric`. (#4428)
+
+### Deprecated
+
+- The `go.opentelemetry.io/otel/exporters/jaeger` package is deprecated.
+  OpenTelemetry dropped support for Jaeger exporter in July 2023.
+  Use `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`
+  or `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` instead. (#4423)
+- The `go.opentelemetry.io/otel/example/jaeger` package is deprecated. (#4423)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal` package is deprecated. (#4420)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/oconf` package is deprecated. (#4420)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/otest` package is deprecated. (#4420)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/transform` package is deprecated. (#4420)
+- The `go.opentelemetry.io/otel/exporters/otlp/internal` package is deprecated. (#4421)
+- The `go.opentelemetry.io/otel/exporters/otlp/internal/envconfig` package is deprecated. (#4421)
+- The `go.opentelemetry.io/otel/exporters/otlp/internal/retry` package is deprecated. (#4421)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` package is deprecated. (#4425)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/envconfig` package is deprecated. (#4425)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig` package is deprecated. (#4425)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlptracetest` package is deprecated. (#4425)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/retry` package is deprecated. (#4425)
+- The `go.opentelemetry.io/otel/sdk/metric/aggregation` package is deprecated.
+  Use the aggregation types added to `go.opentelemetry.io/otel/sdk/metric` instead. (#4435)
+
+## [1.16.0/0.39.0] 2023-05-18
+
+This release contains the first stable release of the OpenTelemetry Go [metric API].
+Our project stability guarantees now apply to the `go.opentelemetry.io/otel/metric` package.
+See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
+
+### Added
+
+- The `go.opentelemetry.io/otel/semconv/v1.19.0` package.
+  The package contains semantic conventions from the `v1.19.0` version of the OpenTelemetry specification. (#3848)
+- The `go.opentelemetry.io/otel/semconv/v1.20.0` package.
+  The package contains semantic conventions from the `v1.20.0` version of the OpenTelemetry specification. (#4078)
+- The Exponential Histogram data types in `go.opentelemetry.io/otel/sdk/metric/metricdata`. (#4165)
+- OTLP metrics exporter now supports the Exponential Histogram Data Type. (#4222)
+- Fix serialization of `time.Time` zero values in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` packages. (#4271)
+
+### Changed
+
+- Use `strings.Cut()` instead of `string.SplitN()` for better readability and memory use. (#4049)
+- `MeterProvider` returns noop meters once it has been shutdown. (#4154)
+
+### Removed
+
+- The deprecated `go.opentelemetry.io/otel/metric/instrument` package is removed.
+  Use `go.opentelemetry.io/otel/metric` instead. (#4055)
+
+### Fixed
+
+- Fix build for BSD based systems in `go.opentelemetry.io/otel/sdk/resource`. (#4077)
+
+## [1.16.0-rc.1/0.39.0-rc.1] 2023-05-03
+
+This is a release candidate for the v1.16.0/v0.39.0 release.
+That release is expected to include the `v1` release of the OpenTelemetry Go metric API and will provide stability guarantees of that API.
+See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
+
+### Added
+
+- Support global `MeterProvider` in `go.opentelemetry.io/otel`. (#4039)
+  - Use `Meter` for a `metric.Meter` from the global `metric.MeterProvider`.
+  - Use `GetMeterProivder` for a global `metric.MeterProvider`.
+  - Use `SetMeterProivder` to set the global `metric.MeterProvider`.
+
+### Changed
+
+- Move the `go.opentelemetry.io/otel/metric` module to the `stable-v1` module set.
+  This stages the metric API to be released as a stable module. (#4038)
+
+### Removed
+
+- The `go.opentelemetry.io/otel/metric/global` package is removed.
+  Use `go.opentelemetry.io/otel` instead. (#4039)
+
+## [1.15.1/0.38.1] 2023-05-02
+
+### Fixed
+
+- Remove unused imports from `sdk/resource/host_id_bsd.go` which caused build failures. (#4040, #4041)
+
+## [1.15.0/0.38.0] 2023-04-27
+
+### Added
+
+- The `go.opentelemetry.io/otel/metric/embedded` package. (#3916)
+- The `Version` function to `go.opentelemetry.io/otel/sdk` to return the SDK version. (#3949)
+- Add a `WithNamespace` option to `go.opentelemetry.io/otel/exporters/prometheus` to allow users to prefix metrics with a namespace. (#3970)
+- The following configuration types were added to `go.opentelemetry.io/otel/metric/instrument` to be used in the configuration of measurement methods. (#3971)
+  - The `AddConfig` used to hold configuration for addition measurements
+    - `NewAddConfig` used to create a new `AddConfig`
+    - `AddOption` used to configure an `AddConfig`
+  - The `RecordConfig` used to hold configuration for recorded measurements
+    - `NewRecordConfig` used to create a new `RecordConfig`
+    - `RecordOption` used to configure a `RecordConfig`
+  - The `ObserveConfig` used to hold configuration for observed measurements
+    - `NewObserveConfig` used to create a new `ObserveConfig`
+    - `ObserveOption` used to configure an `ObserveConfig`
+- `WithAttributeSet` and `WithAttributes` are added to `go.opentelemetry.io/otel/metric/instrument`.
+  They return an option used during a measurement that defines the attribute Set associated with the measurement. (#3971)
+- The `Version` function to `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` to return the OTLP metrics client version. (#3956)
+- The `Version` function to `go.opentelemetry.io/otel/exporters/otlp/otlptrace` to return the OTLP trace client version. (#3956)
+
+### Changed
+
+- The `Extrema` in `go.opentelemetry.io/otel/sdk/metric/metricdata` is redefined with a generic argument of `[N int64 | float64]`. (#3870)
+- Update all exported interfaces from `go.opentelemetry.io/otel/metric` to embed their corresponding interface from `go.opentelemetry.io/otel/metric/embedded`.
+  This adds an implementation requirement to set the interface default behavior for unimplemented methods. (#3916)
+- Move No-Op implementation from `go.opentelemetry.io/otel/metric` into its own package `go.opentelemetry.io/otel/metric/noop`. (#3941)
+  - `metric.NewNoopMeterProvider` is replaced with `noop.NewMeterProvider`
+- Add all the methods from `"go.opentelemetry.io/otel/trace".SpanContext` to `bridgeSpanContext` by embedding `otel.SpanContext` in `bridgeSpanContext`. (#3966)
+- Wrap `UploadMetrics` error in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/` to improve error message when encountering generic grpc errors. (#3974)
+- The measurement methods for all instruments in `go.opentelemetry.io/otel/metric/instrument` accept an option instead of the variadic `"go.opentelemetry.io/otel/attribute".KeyValue`. (#3971)
+  - The `Int64Counter.Add` method now accepts `...AddOption`
+  - The `Float64Counter.Add` method now accepts `...AddOption`
+  - The `Int64UpDownCounter.Add` method now accepts `...AddOption`
+  - The `Float64UpDownCounter.Add` method now accepts `...AddOption`
+  - The `Int64Histogram.Record` method now accepts `...RecordOption`
+  - The `Float64Histogram.Record` method now accepts `...RecordOption`
+  - The `Int64Observer.Observe` method now accepts `...ObserveOption`
+  - The `Float64Observer.Observe` method now accepts `...ObserveOption`
+- The `Observer` methods in `go.opentelemetry.io/otel/metric` accept an option instead of the variadic `"go.opentelemetry.io/otel/attribute".KeyValue`. (#3971)
+  - The `Observer.ObserveInt64` method now accepts `...ObserveOption`
+  - The `Observer.ObserveFloat64` method now accepts `...ObserveOption`
+- Move global metric back to `go.opentelemetry.io/otel/metric/global` from `go.opentelemetry.io/otel`. (#3986)
+
+### Fixed
+
+- `TracerProvider` allows calling `Tracer()` while it's shutting down.
+  It used to deadlock. (#3924)
+- Use the SDK version for the Telemetry SDK resource detector in `go.opentelemetry.io/otel/sdk/resource`. (#3949)
+- Fix a data race in `SpanProcessor` returned by `NewSimpleSpanProcessor` in `go.opentelemetry.io/otel/sdk/trace`. (#3951)
+- Automatically figure out the default aggregation with `aggregation.Default`. (#3967)
+
+### Deprecated
+
+- The `go.opentelemetry.io/otel/metric/instrument` package is deprecated.
+  Use the equivalent types added to `go.opentelemetry.io/otel/metric` instead. (#4018)
+
+## [1.15.0-rc.2/0.38.0-rc.2] 2023-03-23
+
+This is a release candidate for the v1.15.0/v0.38.0 release.
+That release will include the `v1` release of the OpenTelemetry Go metric API and will provide stability guarantees of that API.
+See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
+
+### Added
+
+- The `WithHostID` option to `go.opentelemetry.io/otel/sdk/resource`. (#3812)
+- The `WithoutTimestamps` option to `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` to sets all timestamps to zero. (#3828)
+- The new `Exemplar` type is added to `go.opentelemetry.io/otel/sdk/metric/metricdata`.
+  Both the `DataPoint` and `HistogramDataPoint` types from that package have a new field of `Exemplars` containing the sampled exemplars for their timeseries. (#3849)
+- Configuration for each metric instrument in `go.opentelemetry.io/otel/sdk/metric/instrument`. (#3895)
+- The internal logging introduces a warning level verbosity equal to `V(1)`. (#3900)
+- Added a log message warning about usage of `SimpleSpanProcessor` in production environments. (#3854)
+
+### Changed
+
+- Optimize memory allocation when creation a new `Set` using `NewSet` or `NewSetWithFiltered` in `go.opentelemetry.io/otel/attribute`. (#3832)
+- Optimize memory allocation when creation new metric instruments in `go.opentelemetry.io/otel/sdk/metric`. (#3832)
+- Avoid creating new objects on all calls to `WithDeferredSetup` and `SkipContextSetup` in OpenTracing bridge. (#3833)
+- The `New` and `Detect` functions from `go.opentelemetry.io/otel/sdk/resource` return errors that wrap underlying errors instead of just containing the underlying error strings. (#3844)
+- Both the `Histogram` and `HistogramDataPoint` are redefined with a generic argument of `[N int64 | float64]` in `go.opentelemetry.io/otel/sdk/metric/metricdata`. (#3849)
+- The metric `Export` interface from `go.opentelemetry.io/otel/sdk/metric` accepts a `*ResourceMetrics` instead of `ResourceMetrics`. (#3853)
+- Rename `Asynchronous` to `Observable` in `go.opentelemetry.io/otel/metric/instrument`. (#3892)
+- Rename `Int64ObserverOption` to `Int64ObservableOption` in `go.opentelemetry.io/otel/metric/instrument`. (#3895)
+- Rename `Float64ObserverOption` to `Float64ObservableOption` in `go.opentelemetry.io/otel/metric/instrument`. (#3895)
+- The internal logging changes the verbosity level of info to `V(4)`, the verbosity level of debug to `V(8)`. (#3900)
+
+### Fixed
+
+- `TracerProvider` consistently doesn't allow to register a `SpanProcessor` after shutdown. (#3845)
+
+### Removed
+
+- The deprecated `go.opentelemetry.io/otel/metric/global` package is removed. (#3829)
+- The unneeded `Synchronous` interface in `go.opentelemetry.io/otel/metric/instrument` was removed. (#3892)
+- The `Float64ObserverConfig` and `NewFloat64ObserverConfig` in `go.opentelemetry.io/otel/sdk/metric/instrument`.
+  Use the added `float64` instrument configuration instead. (#3895)
+- The `Int64ObserverConfig` and `NewInt64ObserverConfig` in `go.opentelemetry.io/otel/sdk/metric/instrument`.
+  Use the added `int64` instrument configuration instead. (#3895)
+- The `NewNoopMeter` function in `go.opentelemetry.io/otel/metric`, use `NewMeterProvider().Meter("")` instead. (#3893)
+
+## [1.15.0-rc.1/0.38.0-rc.1] 2023-03-01
+
+This is a release candidate for the v1.15.0/v0.38.0 release.
+That release will include the `v1` release of the OpenTelemetry Go metric API and will provide stability guarantees of that API.
+See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
+
+This release drops the compatibility guarantee of [Go 1.18].
+
+### Added
+
+- Support global `MeterProvider` in `go.opentelemetry.io/otel`. (#3818)
+  - Use `Meter` for a `metric.Meter` from the global `metric.MeterProvider`.
+  - Use `GetMeterProivder` for a global `metric.MeterProvider`.
+  - Use `SetMeterProivder` to set the global `metric.MeterProvider`.
+
+### Changed
+
+- Dropped compatibility testing for [Go 1.18].
+  The project no longer guarantees support for this version of Go. (#3813)
+
+### Fixed
+
+- Handle empty environment variable as it they were not set. (#3764)
+- Clarify the `httpconv` and `netconv` packages in `go.opentelemetry.io/otel/semconv/*` provide tracing semantic conventions. (#3823)
+- Fix race conditions in `go.opentelemetry.io/otel/exporters/metric/prometheus` that could cause a panic. (#3899)
+- Fix sending nil `scopeInfo` to metrics channel in `go.opentelemetry.io/otel/exporters/metric/prometheus` that could cause a panic in `github.com/prometheus/client_golang/prometheus`. (#3899)
+
+### Deprecated
+
+- The `go.opentelemetry.io/otel/metric/global` package is deprecated.
+  Use `go.opentelemetry.io/otel` instead. (#3818)
+
+### Removed
+
+- The deprecated `go.opentelemetry.io/otel/metric/unit` package is removed. (#3814)
+
+## [1.14.0/0.37.0/0.0.4] 2023-02-27
+
+This release is the last to support [Go 1.18].
+The next release will require at least [Go 1.19].
+
+### Added
+
+- The `event` type semantic conventions are added to `go.opentelemetry.io/otel/semconv/v1.17.0`. (#3697)
+- Support [Go 1.20]. (#3693)
+- The `go.opentelemetry.io/otel/semconv/v1.18.0` package.
+  The package contains semantic conventions from the `v1.18.0` version of the OpenTelemetry specification. (#3719)
+  - The following `const` renames from `go.opentelemetry.io/otel/semconv/v1.17.0` are included:
+    - `OtelScopeNameKey` -> `OTelScopeNameKey`
+    - `OtelScopeVersionKey` -> `OTelScopeVersionKey`
+    - `OtelLibraryNameKey` -> `OTelLibraryNameKey`
+    - `OtelLibraryVersionKey` -> `OTelLibraryVersionKey`
+    - `OtelStatusCodeKey` -> `OTelStatusCodeKey`
+    - `OtelStatusDescriptionKey` -> `OTelStatusDescriptionKey`
+    - `OtelStatusCodeOk` -> `OTelStatusCodeOk`
+    - `OtelStatusCodeError` -> `OTelStatusCodeError`
+  - The following `func` renames from `go.opentelemetry.io/otel/semconv/v1.17.0` are included:
+    - `OtelScopeName` -> `OTelScopeName`
+    - `OtelScopeVersion` -> `OTelScopeVersion`
+    - `OtelLibraryName` -> `OTelLibraryName`
+    - `OtelLibraryVersion` -> `OTelLibraryVersion`
+    - `OtelStatusDescription` -> `OTelStatusDescription`
+- A `IsSampled` method is added to the `SpanContext` implementation in `go.opentelemetry.io/otel/bridge/opentracing` to expose the span sampled state.
+  See the [README](./bridge/opentracing/README.md) for more information. (#3570)
+- The `WithInstrumentationAttributes` option to `go.opentelemetry.io/otel/metric`. (#3738)
+- The `WithInstrumentationAttributes` option to `go.opentelemetry.io/otel/trace`. (#3739)
+- The following environment variables are supported by the periodic `Reader` in `go.opentelemetry.io/otel/sdk/metric`. (#3763)
+  - `OTEL_METRIC_EXPORT_INTERVAL` sets the time between collections and exports.
+  - `OTEL_METRIC_EXPORT_TIMEOUT` sets the timeout an export is attempted.
+
+### Changed
+
+- Fall-back to `TextMapCarrier` when it's not `HttpHeader`s in `go.opentelemetry.io/otel/bridge/opentracing`. (#3679)
+- The `Collect` method of the `"go.opentelemetry.io/otel/sdk/metric".Reader` interface is updated to accept the `metricdata.ResourceMetrics` value the collection will be made into.
+  This change is made to enable memory reuse by SDK users. (#3732)
+- The `WithUnit` option in `go.opentelemetry.io/otel/sdk/metric/instrument` is updated to accept a `string` for the unit value. (#3776)
+
+### Fixed
+
+- Ensure `go.opentelemetry.io/otel` does not use generics. (#3723, #3725)
+- Multi-reader `MeterProvider`s now export metrics for all readers, instead of just the first reader. (#3720, #3724)
+- Remove use of deprecated `"math/rand".Seed` in `go.opentelemetry.io/otel/example/prometheus`. (#3733)
+- Do not silently drop unknown schema data with `Parse` in  `go.opentelemetry.io/otel/schema/v1.1`. (#3743)
+- Data race issue in OTLP exporter retry mechanism. (#3755, #3756)
+- Wrapping empty errors when exporting in `go.opentelemetry.io/otel/sdk/metric`. (#3698, #3772)
+- Incorrect "all" and "resource" definition for schema files in `go.opentelemetry.io/otel/schema/v1.1`. (#3777)
+
+### Deprecated
+
+- The `go.opentelemetry.io/otel/metric/unit` package is deprecated.
+  Use the equivalent unit string instead. (#3776)
+  - Use `"1"` instead of `unit.Dimensionless`
+  - Use `"By"` instead of `unit.Bytes`
+  - Use `"ms"` instead of `unit.Milliseconds`
+
+## [1.13.0/0.36.0] 2023-02-07
+
+### Added
+
+- Attribute `KeyValue` creations functions to `go.opentelemetry.io/otel/semconv/v1.17.0` for all non-enum semantic conventions.
+  These functions ensure semantic convention type correctness. (#3675)
+
+### Fixed
+
+- Removed the `http.target` attribute from being added by `ServerRequest` in the following packages. (#3687)
+  - `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`
+  - `go.opentelemetry.io/otel/semconv/v1.14.0/httpconv`
+  - `go.opentelemetry.io/otel/semconv/v1.15.0/httpconv`
+  - `go.opentelemetry.io/otel/semconv/v1.16.0/httpconv`
+  - `go.opentelemetry.io/otel/semconv/v1.17.0/httpconv`
+
+### Removed
+
+- The deprecated `go.opentelemetry.io/otel/metric/instrument/asyncfloat64` package is removed. (#3631)
+- The deprecated `go.opentelemetry.io/otel/metric/instrument/asyncint64` package is removed. (#3631)
+- The deprecated `go.opentelemetry.io/otel/metric/instrument/syncfloat64` package is removed. (#3631)
+- The deprecated `go.opentelemetry.io/otel/metric/instrument/syncint64` package is removed. (#3631)
+
+## [1.12.0/0.35.0] 2023-01-28
+
+### Added
+
+- The `WithInt64Callback` option to `go.opentelemetry.io/otel/metric/instrument`.
+  This options is used to configure `int64` Observer callbacks during their creation. (#3507)
+- The `WithFloat64Callback` option to `go.opentelemetry.io/otel/metric/instrument`.
+  This options is used to configure `float64` Observer callbacks during their creation. (#3507)
+- The `Producer` interface and `Reader.RegisterProducer(Producer)` to `go.opentelemetry.io/otel/sdk/metric`.
+  These additions are used to enable external metric Producers. (#3524)
+- The `Callback` function type to `go.opentelemetry.io/otel/metric`.
+  This new named function type is registered with a `Meter`. (#3564)
+- The `go.opentelemetry.io/otel/semconv/v1.13.0` package.
+  The package contains semantic conventions from the `v1.13.0` version of the OpenTelemetry specification. (#3499)
+  - The `EndUserAttributesFromHTTPRequest` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is merged into `ClientRequest` and `ServerRequest` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `HTTPAttributesFromHTTPStatusCode` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is merged into `ClientResponse` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `HTTPClientAttributesFromHTTPRequest` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is replaced by `ClientRequest` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `HTTPServerAttributesFromHTTPRequest` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is replaced by `ServerRequest` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `HTTPServerMetricAttributesFromHTTPRequest` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is replaced by `ServerRequest` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `NetAttributesFromHTTPRequest` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is split into `Transport` in `go.opentelemetry.io/otel/semconv/v1.13.0/netconv` and `ClientRequest` or `ServerRequest` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `SpanStatusFromHTTPStatusCode` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is replaced by `ClientStatus` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `SpanStatusFromHTTPStatusCodeAndSpanKind` function in `go.opentelemetry.io/otel/semconv/v1.12.0` is split into `ClientStatus` and `ServerStatus` in `go.opentelemetry.io/otel/semconv/v1.13.0/httpconv`.
+  - The `Client` function is included in `go.opentelemetry.io/otel/semconv/v1.13.0/netconv` to generate attributes for a `net.Conn`.
+  - The `Server` function is included in `go.opentelemetry.io/otel/semconv/v1.13.0/netconv` to generate attributes for a `net.Listener`.
+- The `go.opentelemetry.io/otel/semconv/v1.14.0` package.
+  The package contains semantic conventions from the `v1.14.0` version of the OpenTelemetry specification. (#3566)
+- The `go.opentelemetry.io/otel/semconv/v1.15.0` package.
+  The package contains semantic conventions from the `v1.15.0` version of the OpenTelemetry specification. (#3578)
+- The `go.opentelemetry.io/otel/semconv/v1.16.0` package.
+  The package contains semantic conventions from the `v1.16.0` version of the OpenTelemetry specification. (#3579)
+- Metric instruments to `go.opentelemetry.io/otel/metric/instrument`.
+  These instruments are use as replacements of the deprecated `go.opentelemetry.io/otel/metric/instrument/{asyncfloat64,asyncint64,syncfloat64,syncint64}` packages.(#3575, #3586)
+  - `Float64ObservableCounter` replaces the `asyncfloat64.Counter`
+  - `Float64ObservableUpDownCounter` replaces the `asyncfloat64.UpDownCounter`
+  - `Float64ObservableGauge` replaces the `asyncfloat64.Gauge`
+  - `Int64ObservableCounter` replaces the `asyncint64.Counter`
+  - `Int64ObservableUpDownCounter` replaces the `asyncint64.UpDownCounter`
+  - `Int64ObservableGauge` replaces the `asyncint64.Gauge`
+  - `Float64Counter` replaces the `syncfloat64.Counter`
+  - `Float64UpDownCounter` replaces the `syncfloat64.UpDownCounter`
+  - `Float64Histogram` replaces the `syncfloat64.Histogram`
+  - `Int64Counter` replaces the `syncint64.Counter`
+  - `Int64UpDownCounter` replaces the `syncint64.UpDownCounter`
+  - `Int64Histogram` replaces the `syncint64.Histogram`
+- `NewTracerProvider` to `go.opentelemetry.io/otel/bridge/opentracing`.
+  This is used to create `WrapperTracer` instances from a `TracerProvider`. (#3116)
+- The `Extrema` type to `go.opentelemetry.io/otel/sdk/metric/metricdata`.
+  This type is used to represent min/max values and still be able to distinguish unset and zero values. (#3487)
+- The `go.opentelemetry.io/otel/semconv/v1.17.0` package.
+  The package contains semantic conventions from the `v1.17.0` version of the OpenTelemetry specification. (#3599)
+
+### Changed
+
+- Jaeger and Zipkin exporter use `github.com/go-logr/logr` as the logging interface, and add the `WithLogr` option. (#3497, #3500)
+- Instrument configuration in `go.opentelemetry.io/otel/metric/instrument` is split into specific options and configuration based on the instrument type. (#3507)
+  - Use the added `Int64Option` type to configure instruments from `go.opentelemetry.io/otel/metric/instrument/syncint64`.
+  - Use the added `Float64Option` type to configure instruments from `go.opentelemetry.io/otel/metric/instrument/syncfloat64`.
+  - Use the added `Int64ObserverOption` type to configure instruments from `go.opentelemetry.io/otel/metric/instrument/asyncint64`.
+  - Use the added `Float64ObserverOption` type to configure instruments from `go.opentelemetry.io/otel/metric/instrument/asyncfloat64`.
+- Return a `Registration` from the `RegisterCallback` method of a `Meter` in the `go.opentelemetry.io/otel/metric` package.
+  This `Registration` can be used to unregister callbacks. (#3522)
+- Global error handler uses an atomic value instead of a mutex. (#3543)
+- Add `NewMetricProducer` to `go.opentelemetry.io/otel/bridge/opencensus`, which can be used to pass OpenCensus metrics to an OpenTelemetry Reader. (#3541)
+- Global logger uses an atomic value instead of a mutex. (#3545)
+- The `Shutdown` method of the `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` releases all computational resources when called the first time. (#3551)
+- The `Sampler` returned from `TraceIDRatioBased` `go.opentelemetry.io/otel/sdk/trace` now uses the rightmost bits for sampling decisions.
+  This fixes random sampling when using ID generators like `xray.IDGenerator` and increasing parity with other language implementations. (#3557)
+- Errors from `go.opentelemetry.io/otel/exporters/otlp/otlptrace` exporters are wrapped in errors identifying their signal name.
+  Existing users of the exporters attempting to identify specific errors will need to use `errors.Unwrap()` to get the underlying error. (#3516)
+- Exporters from `go.opentelemetry.io/otel/exporters/otlp` will print the final retryable error message when attempts to retry time out. (#3514)
+- The instrument kind names in `go.opentelemetry.io/otel/sdk/metric` are updated to match the API. (#3562)
+  - `InstrumentKindSyncCounter` is renamed to `InstrumentKindCounter`
+  - `InstrumentKindSyncUpDownCounter` is renamed to `InstrumentKindUpDownCounter`
+  - `InstrumentKindSyncHistogram` is renamed to `InstrumentKindHistogram`
+  - `InstrumentKindAsyncCounter` is renamed to `InstrumentKindObservableCounter`
+  - `InstrumentKindAsyncUpDownCounter` is renamed to `InstrumentKindObservableUpDownCounter`
+  - `InstrumentKindAsyncGauge` is renamed to `InstrumentKindObservableGauge`
+- The `RegisterCallback` method of the `Meter` in `go.opentelemetry.io/otel/metric` changed.
+  - The named `Callback` replaces the inline function parameter. (#3564)
+  - `Callback` is required to return an error. (#3576)
+  - `Callback` accepts the added `Observer` parameter added.
+    This new parameter is used by `Callback` implementations to observe values for asynchronous instruments instead of calling the `Observe` method of the instrument directly. (#3584)
+  - The slice of `instrument.Asynchronous` is now passed as a variadic argument. (#3587)
+- The exporter from `go.opentelemetry.io/otel/exporters/zipkin` is updated to use the `v1.16.0` version of semantic conventions.
+  This means it no longer uses the removed `net.peer.ip` or `http.host` attributes to determine the remote endpoint.
+  Instead it uses the `net.sock.peer` attributes. (#3581)
+- The `Min` and `Max` fields of the `HistogramDataPoint` in `go.opentelemetry.io/otel/sdk/metric/metricdata` are now defined with the added `Extrema` type instead of a `*float64`. (#3487)
+
+### Fixed
+
+- Asynchronous instruments that use sum aggregators and attribute filters correctly add values from equivalent attribute sets that have been filtered. (#3439, #3549)
+- The `RegisterCallback` method of the `Meter` from `go.opentelemetry.io/otel/sdk/metric` only registers a callback for instruments created by that meter.
+  Trying to register a callback with instruments from a different meter will result in an error being returned. (#3584)
+
+### Deprecated
+
+- The `NewMetricExporter` in `go.opentelemetry.io/otel/bridge/opencensus` is deprecated.
+  Use `NewMetricProducer` instead. (#3541)
+- The `go.opentelemetry.io/otel/metric/instrument/asyncfloat64` package is deprecated.
+  Use the instruments from `go.opentelemetry.io/otel/metric/instrument` instead. (#3575)
+- The `go.opentelemetry.io/otel/metric/instrument/asyncint64` package is deprecated.
+  Use the instruments from `go.opentelemetry.io/otel/metric/instrument` instead. (#3575)
+- The `go.opentelemetry.io/otel/metric/instrument/syncfloat64` package is deprecated.
+  Use the instruments from `go.opentelemetry.io/otel/metric/instrument` instead. (#3575)
+- The `go.opentelemetry.io/otel/metric/instrument/syncint64` package is deprecated.
+  Use the instruments from `go.opentelemetry.io/otel/metric/instrument` instead. (#3575)
+- The `NewWrappedTracerProvider` in `go.opentelemetry.io/otel/bridge/opentracing` is now deprecated.
+  Use `NewTracerProvider` instead. (#3116)
+
+### Removed
+
+- The deprecated `go.opentelemetry.io/otel/sdk/metric/view` package is removed. (#3520)
+- The `InstrumentProvider` from `go.opentelemetry.io/otel/sdk/metric/asyncint64` is removed.
+  Use the new creation methods of the `Meter` in `go.opentelemetry.io/otel/sdk/metric` instead. (#3530)
+  - The `Counter` method is replaced by `Meter.Int64ObservableCounter`
+  - The `UpDownCounter` method is replaced by `Meter.Int64ObservableUpDownCounter`
+  - The `Gauge` method is replaced by `Meter.Int64ObservableGauge`
+- The `InstrumentProvider` from `go.opentelemetry.io/otel/sdk/metric/asyncfloat64` is removed.
+  Use the new creation methods of the `Meter` in `go.opentelemetry.io/otel/sdk/metric` instead. (#3530)
+  - The `Counter` method is replaced by `Meter.Float64ObservableCounter`
+  - The `UpDownCounter` method is replaced by `Meter.Float64ObservableUpDownCounter`
+  - The `Gauge` method is replaced by `Meter.Float64ObservableGauge`
+- The `InstrumentProvider` from `go.opentelemetry.io/otel/sdk/metric/syncint64` is removed.
+  Use the new creation methods of the `Meter` in `go.opentelemetry.io/otel/sdk/metric` instead. (#3530)
+  - The `Counter` method is replaced by `Meter.Int64Counter`
+  - The `UpDownCounter` method is replaced by `Meter.Int64UpDownCounter`
+  - The `Histogram` method is replaced by `Meter.Int64Histogram`
+- The `InstrumentProvider` from `go.opentelemetry.io/otel/sdk/metric/syncfloat64` is removed.
+  Use the new creation methods of the `Meter` in `go.opentelemetry.io/otel/sdk/metric` instead. (#3530)
+  - The `Counter` method is replaced by `Meter.Float64Counter`
+  - The `UpDownCounter` method is replaced by `Meter.Float64UpDownCounter`
+  - The `Histogram` method is replaced by `Meter.Float64Histogram`
+
+## [1.11.2/0.34.0] 2022-12-05
+
+### Added
+
+- The `WithView` `Option` is added to the `go.opentelemetry.io/otel/sdk/metric` package.
+   This option is used to configure the view(s) a `MeterProvider` will use for all `Reader`s that are registered with it. (#3387)
+- Add Instrumentation Scope and Version as info metric and label in Prometheus exporter.
+  This can be disabled using the `WithoutScopeInfo()` option added to that package.(#3273, #3357)
+- OTLP exporters now recognize: (#3363)
+  - `OTEL_EXPORTER_OTLP_INSECURE`
+  - `OTEL_EXPORTER_OTLP_TRACES_INSECURE`
+  - `OTEL_EXPORTER_OTLP_METRICS_INSECURE`
+  - `OTEL_EXPORTER_OTLP_CLIENT_KEY`
+  - `OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY`
+  - `OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY`
+  - `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE`
+  - `OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE`
+  - `OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE`
+- The `View` type and related `NewView` function to create a view according to the OpenTelemetry specification are added to `go.opentelemetry.io/otel/sdk/metric`.
+  These additions are replacements for the `View` type and `New` function from `go.opentelemetry.io/otel/sdk/metric/view`. (#3459)
+- The `Instrument` and `InstrumentKind` type are added to `go.opentelemetry.io/otel/sdk/metric`.
+  These additions are replacements for the `Instrument` and `InstrumentKind` types from `go.opentelemetry.io/otel/sdk/metric/view`. (#3459)
+- The `Stream` type is added to `go.opentelemetry.io/otel/sdk/metric` to define a metric data stream a view will produce. (#3459)
+- The `AssertHasAttributes` allows instrument authors to test that datapoints returned have appropriate attributes. (#3487)
+
+### Changed
+
+- The `"go.opentelemetry.io/otel/sdk/metric".WithReader` option no longer accepts views to associate with the `Reader`.
+   Instead, views are now registered directly with the `MeterProvider` via the new `WithView` option.
+   The views registered with the `MeterProvider` apply to all `Reader`s. (#3387)
+- The `Temporality(view.InstrumentKind) metricdata.Temporality` and `Aggregation(view.InstrumentKind) aggregation.Aggregation` methods are added to the `"go.opentelemetry.io/otel/sdk/metric".Exporter` interface. (#3260)
+- The `Temporality(view.InstrumentKind) metricdata.Temporality` and `Aggregation(view.InstrumentKind) aggregation.Aggregation` methods are added to the `"go.opentelemetry.io/otel/exporters/otlp/otlpmetric".Client` interface. (#3260)
+- The `WithTemporalitySelector` and `WithAggregationSelector` `ReaderOption`s have been changed to `ManualReaderOption`s in the `go.opentelemetry.io/otel/sdk/metric` package. (#3260)
+- The periodic reader in the `go.opentelemetry.io/otel/sdk/metric` package now uses the temporality and aggregation selectors from its configured exporter instead of accepting them as options. (#3260)
+
+### Fixed
+
+- The `go.opentelemetry.io/otel/exporters/prometheus` exporter fixes duplicated `_total` suffixes. (#3369)
+- Remove comparable requirement for `Reader`s. (#3387)
+- Cumulative metrics from the OpenCensus bridge (`go.opentelemetry.io/otel/bridge/opencensus`) are defined as monotonic sums, instead of non-monotonic. (#3389)
+- Asynchronous counters (`Counter` and `UpDownCounter`) from the metric SDK now produce delta sums when configured with delta temporality. (#3398)
+- Exported `Status` codes in the `go.opentelemetry.io/otel/exporters/zipkin` exporter are now exported as all upper case values. (#3340)
+- `Aggregation`s from `go.opentelemetry.io/otel/sdk/metric` with no data are not exported. (#3394, #3436)
+- Re-enabled Attribute Filters in the Metric SDK. (#3396)
+- Asynchronous callbacks are only called if they are registered with at least one instrument that does not use drop aggragation. (#3408)
+- Do not report empty partial-success responses in the `go.opentelemetry.io/otel/exporters/otlp` exporters. (#3438, #3432)
+- Handle partial success responses in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` exporters. (#3162, #3440)
+- Prevent duplicate Prometheus description, unit, and type. (#3469)
+- Prevents panic when using incorrect `attribute.Value.As[Type]Slice()`. (#3489)
+
+### Removed
+
+- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric.Client` interface is removed. (#3486)
+- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric.New` function is removed. Use the `otlpmetric[http|grpc].New` directly. (#3486)
+
+### Deprecated
+
+- The `go.opentelemetry.io/otel/sdk/metric/view` package is deprecated.
+  Use `Instrument`, `InstrumentKind`, `View`, and `NewView` in `go.opentelemetry.io/otel/sdk/metric` instead. (#3476)
+
+## [1.11.1/0.33.0] 2022-10-19
+
+### Added
+
+- The Prometheus exporter in `go.opentelemetry.io/otel/exporters/prometheus` registers with a Prometheus registerer on creation.
+   By default, it will register with the default Prometheus registerer.
+   A non-default registerer can be used by passing the `WithRegisterer` option. (#3239)
+- Added the `WithAggregationSelector` option to the `go.opentelemetry.io/otel/exporters/prometheus` package to change the default `AggregationSelector` used. (#3341)
+- The Prometheus exporter in `go.opentelemetry.io/otel/exporters/prometheus` converts the `Resource` associated with metric exports into a `target_info` metric. (#3285)
+
+### Changed
+
+- The `"go.opentelemetry.io/otel/exporters/prometheus".New` function is updated to return an error.
+   It will return an error if the exporter fails to register with Prometheus. (#3239)
+
+### Fixed
+
+- The URL-encoded values from the `OTEL_RESOURCE_ATTRIBUTES` environment variable are decoded. (#2963)
+- The `baggage.NewMember` function decodes the `value` parameter instead of directly using it.
+   This fixes the implementation to be compliant with the W3C specification. (#3226)
+- Slice attributes of the `attribute` package are now comparable based on their value, not instance. (#3108 #3252)
+- The `Shutdown` and `ForceFlush` methods of the `"go.opentelemetry.io/otel/sdk/trace".TraceProvider` no longer return an error when no processor is registered. (#3268)
+- The Prometheus exporter in `go.opentelemetry.io/otel/exporters/prometheus` cumulatively sums histogram buckets. (#3281)
+- The sum of each histogram data point is now uniquely exported by the `go.opentelemetry.io/otel/exporters/otlpmetric` exporters. (#3284, #3293)
+- Recorded values for asynchronous counters (`Counter` and `UpDownCounter`) are interpreted as exact, not incremental, sum values by the metric SDK. (#3350, #3278)
+- `UpDownCounters` are now correctly output as Prometheus gauges in the `go.opentelemetry.io/otel/exporters/prometheus` exporter. (#3358)
+- The Prometheus exporter in `go.opentelemetry.io/otel/exporters/prometheus` no longer describes the metrics it will send to Prometheus on startup.
+   Instead the exporter is defined as an "unchecked" collector for Prometheus.
+   This fixes the `reader is not registered` warning currently emitted on startup. (#3291 #3342)
+- The `go.opentelemetry.io/otel/exporters/prometheus` exporter now correctly adds `_total` suffixes to counter metrics. (#3360)
+- The `go.opentelemetry.io/otel/exporters/prometheus` exporter now adds a unit suffix to metric names.
+   This can be disabled using the `WithoutUnits()` option added to that package. (#3352)
+
+## [1.11.0/0.32.3] 2022-10-12
+
+### Added
+
+- Add default User-Agent header to OTLP exporter requests (`go.opentelemetry.io/otel/exporters/otlptrace/otlptracegrpc` and `go.opentelemetry.io/otel/exporters/otlptrace/otlptracehttp`). (#3261)
+
+### Changed
+
+- `span.SetStatus` has been updated such that calls that lower the status are now no-ops. (#3214)
+- Upgrade `golang.org/x/sys/unix` from `v0.0.0-20210423185535-09eb48e85fd7` to `v0.0.0-20220919091848-fb04ddd9f9c8`.
+  This addresses [GO-2022-0493](https://pkg.go.dev/vuln/GO-2022-0493). (#3235)
+
+## [0.32.2] Metric SDK (Alpha) - 2022-10-11
+
+### Added
+
+- Added an example of using metric views to customize instruments. (#3177)
+- Add default User-Agent header to OTLP exporter requests (`go.opentelemetry.io/otel/exporters/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlpmetric/otlpmetrichttp`). (#3261)
+
+### Changed
+
+- Flush pending measurements with the `PeriodicReader` in the `go.opentelemetry.io/otel/sdk/metric` when `ForceFlush` or `Shutdown` are called. (#3220)
+- Update histogram default bounds to match the requirements of the latest specification. (#3222)
+- Encode the HTTP status code in the OpenTracing bridge (`go.opentelemetry.io/otel/bridge/opentracing`) as an integer.  (#3265)
+
+### Fixed
+
+- Use default view if instrument does not match any registered view of a reader. (#3224, #3237)
+- Return the same instrument every time a user makes the exact same instrument creation call. (#3229, #3251)
+- Return the existing instrument when a view transforms a creation call to match an existing instrument. (#3240, #3251)
+- Log a warning when a conflicting instrument (e.g. description, unit, data-type) is created instead of returning an error. (#3251)
+- The OpenCensus bridge no longer sends empty batches of metrics. (#3263)
+
+## [0.32.1] Metric SDK (Alpha) - 2022-09-22
+
+### Changed
+
+- The Prometheus exporter sanitizes OpenTelemetry instrument names when exporting.
+   Invalid characters are replaced with `_`. (#3212)
+
+### Added
+
+- The metric portion of the OpenCensus bridge (`go.opentelemetry.io/otel/bridge/opencensus`) has been reintroduced. (#3192)
+- The OpenCensus bridge example (`go.opentelemetry.io/otel/example/opencensus`) has been reintroduced. (#3206)
+
+### Fixed
+
+- Updated go.mods to point to valid versions of the sdk. (#3216)
+- Set the `MeterProvider` resource on all exported metric data. (#3218)
+
+## [0.32.0] Revised Metric SDK (Alpha) - 2022-09-18
+
+### Changed
+
+- The metric SDK in `go.opentelemetry.io/otel/sdk/metric` is completely refactored to comply with the OpenTelemetry specification.
+  Please see the package documentation for how the new SDK is initialized and configured. (#3175)
+- Update the minimum supported go version to go1.18. Removes support for go1.17 (#3179)
+
+### Removed
+
+- The metric portion of the OpenCensus bridge (`go.opentelemetry.io/otel/bridge/opencensus`) has been removed.
+  A new bridge compliant with the revised metric SDK will be added back in a future release. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/aggregator/histogram` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/aggregator/sum` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/aggregator` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/controller/basic` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/controller/controllertest` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/controller/time` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/export/aggregation` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/export` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/metrictest` package is removed.
+  A replacement package that supports the new metric SDK will be added back in a future release. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/number` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/processor/basic` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/processor/processortest` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/processor/reducer` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/registry` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/sdkapi` package is removed, see the new metric SDK. (#3175)
+- The `go.opentelemetry.io/otel/sdk/metric/selector/simple` package is removed, see the new metric SDK. (#3175)
+- The `"go.opentelemetry.io/otel/sdk/metric".ErrUninitializedInstrument` variable was removed. (#3175)
+- The `"go.opentelemetry.io/otel/sdk/metric".ErrBadInstrument` variable was removed. (#3175)
+- The `"go.opentelemetry.io/otel/sdk/metric".Accumulator` type was removed, see the `MeterProvider`in the new metric SDK. (#3175)
+- The `"go.opentelemetry.io/otel/sdk/metric".NewAccumulator` function was removed, see `NewMeterProvider`in the new metric SDK. (#3175)
+- The deprecated `"go.opentelemetry.io/otel/sdk/metric".AtomicFieldOffsets` function was removed. (#3175)
+
+## [1.10.0] - 2022-09-09
+
+### Added
+
+- Support Go 1.19. (#3077)
+  Include compatibility testing and document support. (#3077)
+- Support the OTLP ExportTracePartialSuccess response; these are passed to the registered error handler. (#3106)
+- Upgrade go.opentelemetry.io/proto/otlp from v0.18.0 to v0.19.0 (#3107)
+
+### Changed
+
+- Fix misidentification of OpenTelemetry `SpanKind` in OpenTracing bridge (`go.opentelemetry.io/otel/bridge/opentracing`).  (#3096)
+- Attempting to start a span with a nil `context` will no longer cause a panic. (#3110)
+- All exporters will be shutdown even if one reports an error (#3091)
+- Ensure valid UTF-8 when truncating over-length attribute values. (#3156)
+
+## [1.9.0/0.0.3] - 2022-08-01
+
+### Added
+
+- Add support for Schema Files format 1.1.x (metric "split" transform) with the new `go.opentelemetry.io/otel/schema/v1.1` package. (#2999)
+- Add the `go.opentelemetry.io/otel/semconv/v1.11.0` package.
+  The package contains semantic conventions from the `v1.11.0` version of the OpenTelemetry specification. (#3009)
+- Add the `go.opentelemetry.io/otel/semconv/v1.12.0` package.
+  The package contains semantic conventions from the `v1.12.0` version of the OpenTelemetry specification. (#3010)
+- Add the `http.method` attribute to HTTP server metric from all `go.opentelemetry.io/otel/semconv/*` packages. (#3018)
+
+### Fixed
+
+- Invalid warning for context setup being deferred in `go.opentelemetry.io/otel/bridge/opentracing` package. (#3029)
+
+## [1.8.0/0.31.0] - 2022-07-08
+
+### Added
+
+- Add support for `opentracing.TextMap` format in the `Inject` and `Extract` methods
+of the `"go.opentelemetry.io/otel/bridge/opentracing".BridgeTracer` type. (#2911)
+
+### Changed
+
+- The `crosslink` make target has been updated to use the `go.opentelemetry.io/build-tools/crosslink` package. (#2886)
+- In the `go.opentelemetry.io/otel/sdk/instrumentation` package rename `Library` to `Scope` and alias `Library` as `Scope` (#2976)
+- Move metric no-op implementation form `nonrecording` to `metric` package. (#2866)
+
+### Removed
+
+- Support for go1.16. Support is now only for go1.17 and go1.18 (#2917)
+
+### Deprecated
+
+- The `Library` struct in the `go.opentelemetry.io/otel/sdk/instrumentation` package is deprecated.
+  Use the equivalent `Scope` struct instead. (#2977)
+- The `ReadOnlySpan.InstrumentationLibrary` method from the `go.opentelemetry.io/otel/sdk/trace` package is deprecated.
+  Use the equivalent `ReadOnlySpan.InstrumentationScope` method instead. (#2977)
+
+## [1.7.0/0.30.0] - 2022-04-28
+
+### Added
+
+- Add the `go.opentelemetry.io/otel/semconv/v1.8.0` package.
+  The package contains semantic conventions from the `v1.8.0` version of the OpenTelemetry specification. (#2763)
+- Add the `go.opentelemetry.io/otel/semconv/v1.9.0` package.
+  The package contains semantic conventions from the `v1.9.0` version of the OpenTelemetry specification. (#2792)
+- Add the `go.opentelemetry.io/otel/semconv/v1.10.0` package.
+  The package contains semantic conventions from the `v1.10.0` version of the OpenTelemetry specification. (#2842)
+- Added an in-memory exporter to metrictest to aid testing with a full SDK. (#2776)
+
+### Fixed
+
+- Globally delegated instruments are unwrapped before delegating asynchronous callbacks. (#2784)
+- Remove import of `testing` package in non-tests builds of the `go.opentelemetry.io/otel` package. (#2786)
+
+### Changed
+
+- The `WithLabelEncoder` option from the `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` package is renamed to `WithAttributeEncoder`. (#2790)
+- The `LabelFilterSelector` interface from `go.opentelemetry.io/otel/sdk/metric/processor/reducer` is renamed to `AttributeFilterSelector`.
+  The method included in the renamed interface also changed from `LabelFilterFor` to `AttributeFilterFor`. (#2790)
+- The `Metadata.Labels` method from the `go.opentelemetry.io/otel/sdk/metric/export` package is renamed to `Metadata.Attributes`.
+  Consequentially, the `Record` type from the same package also has had the embedded method renamed. (#2790)
+
+### Deprecated
+
+- The `Iterator.Label` method in the `go.opentelemetry.io/otel/attribute` package is deprecated.
+  Use the equivalent `Iterator.Attribute` method instead. (#2790)
+- The `Iterator.IndexedLabel` method in the `go.opentelemetry.io/otel/attribute` package is deprecated.
+  Use the equivalent `Iterator.IndexedAttribute` method instead. (#2790)
+- The `MergeIterator.Label` method in the `go.opentelemetry.io/otel/attribute` package is deprecated.
+  Use the equivalent `MergeIterator.Attribute` method instead. (#2790)
+
+### Removed
+
+- Removed the `Batch` type from the `go.opentelemetry.io/otel/sdk/metric/metrictest` package. (#2864)
+- Removed the `Measurement` type from the `go.opentelemetry.io/otel/sdk/metric/metrictest` package. (#2864)
+
+## [0.29.0] - 2022-04-11
+
+### Added
+
+- The metrics global package was added back into several test files. (#2764)
+- The `Meter` function is added back to the `go.opentelemetry.io/otel/metric/global` package.
+  This function is a convenience function equivalent to calling `global.MeterProvider().Meter(...)`. (#2750)
+
+### Removed
+
+- Removed module the `go.opentelemetry.io/otel/sdk/export/metric`.
+  Use the `go.opentelemetry.io/otel/sdk/metric` module instead. (#2720)
+
+### Changed
+
+- Don't panic anymore when setting a global MeterProvider to itself. (#2749)
+- Upgrade `go.opentelemetry.io/proto/otlp` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` from `v0.12.1` to `v0.15.0`.
+  This replaces the use of the now deprecated `InstrumentationLibrary` and `InstrumentationLibraryMetrics` types and fields in the proto library with the equivalent `InstrumentationScope` and `ScopeMetrics`. (#2748)
+
+## [1.6.3] - 2022-04-07
+
+### Fixed
+
+- Allow non-comparable global `MeterProvider`, `TracerProvider`, and `TextMapPropagator` types to be set. (#2772, #2773)
+
+## [1.6.2] - 2022-04-06
+
+### Changed
+
+- Don't panic anymore when setting a global TracerProvider or TextMapPropagator to itself. (#2749)
+- Upgrade `go.opentelemetry.io/proto/otlp` in `go.opentelemetry.io/otel/exporters/otlp/otlptrace` from `v0.12.1` to `v0.15.0`.
+  This replaces the use of the now deprecated `InstrumentationLibrary` and `InstrumentationLibrarySpans` types and fields in the proto library with the equivalent `InstrumentationScope` and `ScopeSpans`. (#2748)
+
+## [1.6.1] - 2022-03-28
+
+### Fixed
+
+- The `go.opentelemetry.io/otel/schema/*` packages now use the correct schema URL for their `SchemaURL` constant.
+  Instead of using `"https://opentelemetry.io/schemas/v<version>"` they now use the correct URL without a `v` prefix, `"https://opentelemetry.io/schemas/<version>"`. (#2743, #2744)
+
+### Security
+
+- Upgrade `go.opentelemetry.io/proto/otlp` from `v0.12.0` to `v0.12.1`.
+  This includes an indirect upgrade of `github.com/grpc-ecosystem/grpc-gateway` which resolves [a vulnerability](https://nvd.nist.gov/vuln/detail/CVE-2019-11254) from `gopkg.in/yaml.v2` in version `v2.2.3`. (#2724, #2728)
+
+## [1.6.0/0.28.0] - 2022-03-23
+
+### ⚠️ Notice ⚠️
+
+This update is a breaking change of the unstable Metrics API.
+Code instrumented with the `go.opentelemetry.io/otel/metric` will need to be modified.
+
+### Added
+
+- Add metrics exponential histogram support.
+  New mapping functions have been made available in `sdk/metric/aggregator/exponential/mapping` for other OpenTelemetry projects to take dependencies on. (#2502)
+- Add Go 1.18 to our compatibility tests. (#2679)
+- Allow configuring the Sampler with the `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG` environment variables. (#2305, #2517)
+- Add the `metric/global` for obtaining and setting the global `MeterProvider`. (#2660)
+
+### Changed
+
+- The metrics API has been significantly changed to match the revised OpenTelemetry specification.
+  High-level changes include:
+
+  - Synchronous and asynchronous instruments are now handled by independent `InstrumentProvider`s.
+    These `InstrumentProvider`s are managed with a `Meter`.
+  - Synchronous and asynchronous instruments are grouped into their own packages based on value types.
+  - Asynchronous callbacks can now be registered with a `Meter`.
+
+  Be sure to check out the metric module documentation for more information on how to use the revised API. (#2587, #2660)
+
+### Fixed
+
+- Fallback to general attribute limits when span specific ones are not set in the environment. (#2675, #2677)
+
+## [1.5.0] - 2022-03-16
+
+### Added
+
+- Log the Exporters configuration in the TracerProviders message. (#2578)
+- Added support to configure the span limits with environment variables.
+  The following environment variables are supported. (#2606, #2637)
+  - `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT`
+  - `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT`
+  - `OTEL_SPAN_EVENT_COUNT_LIMIT`
+  - `OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT`
+  - `OTEL_SPAN_LINK_COUNT_LIMIT`
+  - `OTEL_LINK_ATTRIBUTE_COUNT_LIMIT`
+
+  If the provided environment variables are invalid (negative), the default values would be used.
+- Rename the `gc` runtime name to `go` (#2560)
+- Add resource container ID detection. (#2418)
+- Add span attribute value length limit.
+  The new `AttributeValueLengthLimit` field is added to the `"go.opentelemetry.io/otel/sdk/trace".SpanLimits` type to configure this limit for a `TracerProvider`.
+  The default limit for this resource is "unlimited". (#2637)
+- Add the `WithRawSpanLimits` option to `go.opentelemetry.io/otel/sdk/trace`.
+  This option replaces the `WithSpanLimits` option.
+  Zero or negative values will not be changed to the default value like `WithSpanLimits` does.
+  Setting a limit to zero will effectively disable the related resource it limits and setting to a negative value will mean that resource is unlimited.
+  Consequentially, limits should be constructed using `NewSpanLimits` and updated accordingly. (#2637)
+
+### Changed
+
+- Drop oldest tracestate `Member` when capacity is reached. (#2592)
+- Add event and link drop counts to the exported data from the `oltptrace` exporter. (#2601)
+- Unify path cleaning functionally in the `otlpmetric` and `otlptrace` configuration. (#2639)
+- Change the debug message from the `sdk/trace.BatchSpanProcessor` to reflect the count is cumulative. (#2640)
+- Introduce new internal `envconfig` package for OTLP exporters. (#2608)
+- If `http.Request.Host` is empty, fall back to use `URL.Host` when populating `http.host` in the `semconv` packages. (#2661)
+
+### Fixed
+
+- Remove the OTLP trace exporter limit of SpanEvents when exporting. (#2616)
+- Default to port `4318` instead of `4317` for the `otlpmetrichttp` and `otlptracehttp` client. (#2614, #2625)
+- Unlimited span limits are now supported (negative values). (#2636, #2637)
+
+### Deprecated
+
+- Deprecated `"go.opentelemetry.io/otel/sdk/trace".WithSpanLimits`.
+  Use `WithRawSpanLimits` instead.
+  That option allows setting unlimited and zero limits, this option does not.
+  This option will be kept until the next major version incremented release. (#2637)
+
+## [1.4.1] - 2022-02-16
+
+### Fixed
+
+- Fix race condition in reading the dropped spans number for the `BatchSpanProcessor`. (#2615)
+
+## [1.4.0] - 2022-02-11
+
+### Added
+
+- Use `OTEL_EXPORTER_ZIPKIN_ENDPOINT` environment variable to specify zipkin collector endpoint. (#2490)
+- Log the configuration of `TracerProvider`s, and `Tracer`s for debugging.
+  To enable use a logger with Verbosity (V level) `>=1`. (#2500)
+- Added support to configure the batch span-processor with environment variables.
+  The following environment variables are used. (#2515)
+  - `OTEL_BSP_SCHEDULE_DELAY`
+  - `OTEL_BSP_EXPORT_TIMEOUT`
+  - `OTEL_BSP_MAX_QUEUE_SIZE`.
+  - `OTEL_BSP_MAX_EXPORT_BATCH_SIZE`
+
+### Changed
+
+- Zipkin exporter exports `Resource` attributes in the `Tags` field. (#2589)
+
+### Deprecated
+
+- Deprecate module the `go.opentelemetry.io/otel/sdk/export/metric`.
+  Use the `go.opentelemetry.io/otel/sdk/metric` module instead. (#2382)
+- Deprecate `"go.opentelemetry.io/otel/sdk/metric".AtomicFieldOffsets`. (#2445)
+
+### Fixed
+
+- Fixed the instrument kind for noop async instruments to correctly report an implementation. (#2461)
+- Fix UDP packets overflowing with Jaeger payloads. (#2489, #2512)
+- Change the `otlpmetric.Client` interface's `UploadMetrics` method to accept a single `ResourceMetrics` instead of a slice of them. (#2491)
+- Specify explicit buckets in Prometheus example, fixing issue where example only has `+inf` bucket. (#2419, #2493)
+- W3C baggage will now decode urlescaped values. (#2529)
+- Baggage members are now only validated once, when calling `NewMember` and not also when adding it to the baggage itself. (#2522)
+- The order attributes are dropped from spans in the `go.opentelemetry.io/otel/sdk/trace` package when capacity is reached is fixed to be in compliance with the OpenTelemetry specification.
+  Instead of dropping the least-recently-used attribute, the last added attribute is dropped.
+  This drop order still only applies to attributes with unique keys not already contained in the span.
+  If an attribute is added with a key already contained in the span, that attribute is updated to the new value being added. (#2576)
+
+### Removed
+
+- Updated `go.opentelemetry.io/proto/otlp` from `v0.11.0` to `v0.12.0`. This version removes a number of deprecated methods. (#2546)
+  - [`Metric.GetIntGauge()`](https://pkg.go.dev/go.opentelemetry.io/proto/[email protected]/metrics/v1#Metric.GetIntGauge)
+  - [`Metric.GetIntHistogram()`](https://pkg.go.dev/go.opentelemetry.io/proto/[email protected]/metrics/v1#Metric.GetIntHistogram)
+  - [`Metric.GetIntSum()`](https://pkg.go.dev/go.opentelemetry.io/proto/[email protected]/metrics/v1#Metric.GetIntSum)
+
+## [1.3.0] - 2021-12-10
+
+### ⚠️ Notice ⚠️
+
+We have updated the project minimum supported Go version to 1.16
+
+### Added
+
+- Added an internal Logger.
+  This can be used by the SDK and API to provide users with feedback of the internal state.
+  To enable verbose logs configure the logger which will print V(1) logs. For debugging information configure to print V(5) logs. (#2343)
+- Add the `WithRetry` `Option` and the `RetryConfig` type to the `go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetrichttp` package to specify retry behavior consistently. (#2425)
+- Add `SpanStatusFromHTTPStatusCodeAndSpanKind` to all `semconv` packages to return a span status code similar to `SpanStatusFromHTTPStatusCode`, but exclude `4XX` HTTP errors as span errors if the span is of server kind. (#2296)
+
+### Changed
+
+- The `"go.opentelemetry.io/otel/exporter/otel/otlptrace/otlptracegrpc".Client` now uses the underlying gRPC `ClientConn` to handle name resolution, TCP connection establishment (with retries and backoff) and TLS handshakes, and handling errors on established connections by re-resolving the name and reconnecting. (#2329)
+- The `"go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetricgrpc".Client` now uses the underlying gRPC `ClientConn` to handle name resolution, TCP connection establishment (with retries and backoff) and TLS handshakes, and handling errors on established connections by re-resolving the name and reconnecting. (#2425)
+- The `"go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetricgrpc".RetrySettings` type is renamed to `RetryConfig`. (#2425)
+- The `go.opentelemetry.io/otel/exporter/otel/*` gRPC exporters now default to using the host's root CA set if none are provided by the user and `WithInsecure` is not specified. (#2432)
+- Change `resource.Default` to be evaluated the first time it is called, rather than on import. This allows the caller the option to update `OTEL_RESOURCE_ATTRIBUTES` first, such as with `os.Setenv`. (#2371)
+
+### Fixed
+
+- The `go.opentelemetry.io/otel/exporter/otel/*` exporters are updated to handle per-signal and universal endpoints according to the OpenTelemetry specification.
+  Any per-signal endpoint set via an `OTEL_EXPORTER_OTLP_<signal>_ENDPOINT` environment variable is now used without modification of the path.
+  When `OTEL_EXPORTER_OTLP_ENDPOINT` is set, if it contains a path, that path is used as a base path which per-signal paths are appended to. (#2433)
+- Basic metric controller updated to use sync.Map to avoid blocking calls (#2381)
+- The `go.opentelemetry.io/otel/exporter/jaeger` correctly sets the `otel.status_code` value to be a string of `ERROR` or `OK` instead of an integer code. (#2439, #2440)
+
+### Deprecated
+
+- Deprecated the `"go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetrichttp".WithMaxAttempts` `Option`, use the new `WithRetry` `Option` instead. (#2425)
+- Deprecated the `"go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetrichttp".WithBackoff` `Option`, use the new `WithRetry` `Option` instead. (#2425)
+
+### Removed
+
+- Remove the metric Processor's ability to convert cumulative to delta aggregation temporality. (#2350)
+- Remove the metric Bound Instruments interface and implementations. (#2399)
+- Remove the metric MinMaxSumCount kind aggregation and the corresponding OTLP export path. (#2423)
+- Metric SDK removes the "exact" aggregator for histogram instruments, as it performed a non-standard aggregation for OTLP export (creating repeated Gauge points) and worked its way into a number of confusing examples. (#2348)
+
+## [1.2.0] - 2021-11-12
+
+### Changed
+
+- Metric SDK `export.ExportKind`, `export.ExportKindSelector` types have been renamed to `aggregation.Temporality` and `aggregation.TemporalitySelector` respectively to keep in line with current specification and protocol along with built-in selectors (e.g., `aggregation.CumulativeTemporalitySelector`, ...). (#2274)
+- The Metric `Exporter` interface now requires a `TemporalitySelector` method instead of an `ExportKindSelector`. (#2274)
+- Metrics API cleanup. The `metric/sdkapi` package has been created to relocate the API-to-SDK interface:
+  - The following interface types simply moved from `metric` to `metric/sdkapi`: `Descriptor`, `MeterImpl`, `InstrumentImpl`, `SyncImpl`, `BoundSyncImpl`, `AsyncImpl`, `AsyncRunner`, `AsyncSingleRunner`, and `AsyncBatchRunner`
+  - The following struct types moved and are replaced with type aliases, since they are exposed to the user: `Observation`, `Measurement`.
+  - The No-op implementations of sync and async instruments are no longer exported, new functions `sdkapi.NewNoopAsyncInstrument()` and `sdkapi.NewNoopSyncInstrument()` are provided instead. (#2271)
+- Update the SDK `BatchSpanProcessor` to export all queued spans when `ForceFlush` is called. (#2080, #2335)
+
+### Added
+
+- Add the `"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc".WithGRPCConn` option so the exporter can reuse an existing gRPC connection. (#2002)
+- Added a new `schema` module to help parse Schema Files in OTEP 0152 format. (#2267)
+- Added a new `MapCarrier` to the `go.opentelemetry.io/otel/propagation` package to hold propagated cross-cutting concerns as a `map[string]string` held in memory. (#2334)
+
+## [1.1.0] - 2021-10-27
+
+### Added
+
+- Add the `"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc".WithGRPCConn` option so the exporter can reuse an existing gRPC connection. (#2002)
+- Add the `go.opentelemetry.io/otel/semconv/v1.7.0` package.
+  The package contains semantic conventions from the `v1.7.0` version of the OpenTelemetry specification. (#2320)
+- Add the `go.opentelemetry.io/otel/semconv/v1.6.1` package.
+  The package contains semantic conventions from the `v1.6.1` version of the OpenTelemetry specification. (#2321)
+- Add the `go.opentelemetry.io/otel/semconv/v1.5.0` package.
+  The package contains semantic conventions from the `v1.5.0` version of the OpenTelemetry specification. (#2322)
+  - When upgrading from the `semconv/v1.4.0` package note the following name changes:
+    - `K8SReplicasetUIDKey` -> `K8SReplicaSetUIDKey`
+    - `K8SReplicasetNameKey` -> `K8SReplicaSetNameKey`
+    - `K8SStatefulsetUIDKey` -> `K8SStatefulSetUIDKey`
+    - `k8SStatefulsetNameKey` -> `K8SStatefulSetNameKey`
+    - `K8SDaemonsetUIDKey` -> `K8SDaemonSetUIDKey`
+    - `K8SDaemonsetNameKey` -> `K8SDaemonSetNameKey`
+
+### Changed
+
+- Links added to a span will be dropped by the SDK if they contain an invalid span context (#2275).
+
+### Fixed
+
+- The `"go.opentelemetry.io/otel/semconv/v1.4.0".HTTPServerAttributesFromHTTPRequest` now correctly only sets the HTTP client IP attribute even if the connection was routed with proxies and there are multiple addresses in the `X-Forwarded-For` header. (#2282, #2284)
+- The `"go.opentelemetry.io/otel/semconv/v1.4.0".NetAttributesFromHTTPRequest` function correctly handles IPv6 addresses as IP addresses and sets the correct net peer IP instead of the net peer hostname attribute. (#2283, #2285)
+- The simple span processor shutdown method deterministically returns the exporter error status if it simultaneously finishes when the deadline is reached. (#2290, #2289)
+
+## [1.0.1] - 2021-10-01
+
+### Fixed
+
+- json stdout exporter no longer crashes due to concurrency bug. (#2265)
+
+## [Metrics 0.24.0] - 2021-10-01
+
+### Changed
+
+- NoopMeterProvider is now private and NewNoopMeterProvider must be used to obtain a noopMeterProvider. (#2237)
+- The Metric SDK `Export()` function takes a new two-level reader interface for iterating over results one instrumentation library at a time. (#2197)
+  - The former `"go.opentelemetry.io/otel/sdk/export/metric".CheckpointSet` is renamed `Reader`.
+  - The new interface is named `"go.opentelemetry.io/otel/sdk/export/metric".InstrumentationLibraryReader`.
+
+## [1.0.0] - 2021-09-20
+
+This is the first stable release for the project.
+This release includes an API and SDK for the tracing signal that will comply with the stability guarantees defined by the projects [versioning policy](./VERSIONING.md).
+
+### Added
+
+- OTLP trace exporter now sets the `SchemaURL` field in the exported telemetry if the Tracer has `WithSchemaURL` option. (#2242)
+
+### Fixed
+
+- Slice-valued attributes can correctly be used as map keys. (#2223)
+
+### Removed
+
+- Removed the `"go.opentelemetry.io/otel/exporters/zipkin".WithSDKOptions` function. (#2248)
+- Removed the deprecated package `go.opentelemetry.io/otel/oteltest`. (#2234)
+- Removed the deprecated package `go.opentelemetry.io/otel/bridge/opencensus/utils`. (#2233)
+- Removed deprecated functions, types, and methods from `go.opentelemetry.io/otel/attribute` package.
+  Use the typed functions and methods added to the package instead. (#2235)
+  - The `Key.Array` method is removed.
+  - The `Array` function is removed.
+  - The `Any` function is removed.
+  - The `ArrayValue` function is removed.
+  - The `AsArray` function is removed.
+
+## [1.0.0-RC3] - 2021-09-02
+
+### Added
+
+- Added `ErrorHandlerFunc` to use a function as an `"go.opentelemetry.io/otel".ErrorHandler`. (#2149)
+- Added `"go.opentelemetry.io/otel/trace".WithStackTrace` option to add a stack trace when using `span.RecordError` or when panic is handled in `span.End`. (#2163)
+- Added typed slice attribute types and functionality to the `go.opentelemetry.io/otel/attribute` package to replace the existing array type and functions. (#2162)
+  - `BoolSlice`, `IntSlice`, `Int64Slice`, `Float64Slice`, and `StringSlice` replace the use of the `Array` function in the package.
+- Added the `go.opentelemetry.io/otel/example/fib` example package.
+  Included is an example application that computes Fibonacci numbers. (#2203)
+
+### Changed
+
+- Metric instruments have been renamed to match the (feature-frozen) metric API specification:
+  - ValueRecorder becomes Histogram
+  - ValueObserver becomes Gauge
+  - SumObserver becomes CounterObserver
+  - UpDownSumObserver becomes UpDownCounterObserver
+  The API exported from this project is still considered experimental. (#2202)
+- Metric SDK/API implementation type `InstrumentKind` moves into `sdkapi` sub-package. (#2091)
+- The Metrics SDK export record no longer contains a Resource pointer, the SDK `"go.opentelemetry.io/otel/sdk/trace/export/metric".Exporter.Export()` function for push-based exporters now takes a single Resource argument, pull-based exporters use `"go.opentelemetry.io/otel/sdk/metric/controller/basic".Controller.Resource()`. (#2120)
+- The JSON output of the `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` is harmonized now such that the output is "plain" JSON objects after each other of the form `{ ... } { ... } { ... }`. Earlier the JSON objects describing a span were wrapped in a slice for each `Exporter.ExportSpans` call, like `[ { ... } ][ { ... } { ... } ]`. Outputting JSON object directly after each other is consistent with JSON loggers, and a bit easier to parse and read. (#2196)
+- Update the `NewTracerConfig`, `NewSpanStartConfig`, `NewSpanEndConfig`, and `NewEventConfig` function in the `go.opentelemetry.io/otel/trace` package to return their respective configurations as structs instead of pointers to the struct. (#2212)
+
+### Deprecated
+
+- The `go.opentelemetry.io/otel/bridge/opencensus/utils` package is deprecated.
+  All functionality from this package now exists in the `go.opentelemetry.io/otel/bridge/opencensus` package.
+  The functions from that package should be used instead. (#2166)
+- The `"go.opentelemetry.io/otel/attribute".Array` function and the related `ARRAY` value type is deprecated.
+  Use the typed `*Slice` functions and types added to the package instead. (#2162)
+- The `"go.opentelemetry.io/otel/attribute".Any` function is deprecated.
+  Use the typed functions instead. (#2181)
+- The `go.opentelemetry.io/otel/oteltest` package is deprecated.
+  The `"go.opentelemetry.io/otel/sdk/trace/tracetest".SpanRecorder` can be registered with the default SDK (`go.opentelemetry.io/otel/sdk/trace`) as a `SpanProcessor` and used as a replacement for this deprecated package. (#2188)
+
+### Removed
+
+- Removed metrics test package `go.opentelemetry.io/otel/sdk/export/metric/metrictest`. (#2105)
+
+### Fixed
+
+- The `fromEnv` detector no longer throws an error when `OTEL_RESOURCE_ATTRIBUTES` environment variable is not set or empty. (#2138)
+- Setting the global `ErrorHandler` with `"go.opentelemetry.io/otel".SetErrorHandler` multiple times is now supported. (#2160, #2140)
+- The `"go.opentelemetry.io/otel/attribute".Any` function now supports `int32` values. (#2169)
+- Multiple calls to `"go.opentelemetry.io/otel/sdk/metric/controller/basic".WithResource()` are handled correctly, and when no resources are provided `"go.opentelemetry.io/otel/sdk/resource".Default()` is used. (#2120)
+- The `WithoutTimestamps` option for the `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` exporter causes the exporter to correctly omit timestamps. (#2195)
+- Fixed typos in resources.go. (#2201)
+
+## [1.0.0-RC2] - 2021-07-26
+
+### Added
+
+- Added `WithOSDescription` resource configuration option to set OS (Operating System) description resource attribute (`os.description`). (#1840)
+- Added `WithOS` resource configuration option to set all OS (Operating System) resource attributes at once. (#1840)
+- Added the `WithRetry` option to the `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` package.
+  This option is a replacement for the removed `WithMaxAttempts` and `WithBackoff` options. (#2095)
+- Added API `LinkFromContext` to return Link which encapsulates SpanContext from provided context and also encapsulates attributes. (#2115)
+- Added a new `Link` type under the SDK `otel/sdk/trace` package that counts the number of attributes that were dropped for surpassing the `AttributePerLinkCountLimit` configured in the Span's `SpanLimits`.
+  This new type replaces the equal-named API `Link` type found in the `otel/trace` package for most usages within the SDK.
+  For example, instances of this type are now returned by the `Links()` function of `ReadOnlySpan`s provided in places like the `OnEnd` function of `SpanProcessor` implementations. (#2118)
+- Added the `SpanRecorder` type to the `go.opentelemetry.io/otel/skd/trace/tracetest` package.
+  This type can be used with the default SDK as a `SpanProcessor` during testing. (#2132)
+
+### Changed
+
+- The `SpanModels` function is now exported from the `go.opentelemetry.io/otel/exporters/zipkin` package to convert OpenTelemetry spans into Zipkin model spans. (#2027)
+- Rename the `"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc".RetrySettings` to `RetryConfig`. (#2095)
+
+### Deprecated
+
+- The `TextMapCarrier` and `TextMapPropagator` from the `go.opentelemetry.io/otel/oteltest` package and their associated creation functions (`TextMapCarrier`, `NewTextMapPropagator`) are deprecated. (#2114)
+- The `Harness` type from the `go.opentelemetry.io/otel/oteltest` package and its associated creation function, `NewHarness` are deprecated and will be removed in the next release. (#2123)
+- The `TraceStateFromKeyValues` function from the `go.opentelemetry.io/otel/oteltest` package is deprecated.
+  Use the `trace.ParseTraceState` function instead. (#2122)
+
+### Removed
+
+- Removed the deprecated package `go.opentelemetry.io/otel/exporters/trace/jaeger`. (#2020)
+- Removed the deprecated package `go.opentelemetry.io/otel/exporters/trace/zipkin`. (#2020)
+- Removed the `"go.opentelemetry.io/otel/sdk/resource".WithBuiltinDetectors` function.
+  The explicit `With*` options for every built-in detector should be used instead. (#2026 #2097)
+- Removed the `WithMaxAttempts` and `WithBackoff` options from the `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` package.
+  The retry logic of the package has been updated to match the `otlptracegrpc` package and accordingly a `WithRetry` option is added that should be used instead. (#2095)
+- Removed `DroppedAttributeCount` field from `otel/trace.Link` struct. (#2118)
+
+### Fixed
+
+- When using WithNewRoot, don't use the parent context for making sampling decisions. (#2032)
+- `oteltest.Tracer` now creates a valid `SpanContext` when using `WithNewRoot`. (#2073)
+- OS type detector now sets the correct `dragonflybsd` value for DragonFly BSD. (#2092)
+- The OTel span status is correctly transformed into the OTLP status in the `go.opentelemetry.io/otel/exporters/otlp/otlptrace` package.
+  This fix will by default set the status to `Unset` if it is not explicitly set to `Ok` or `Error`. (#2099 #2102)
+- The `Inject` method for the `"go.opentelemetry.io/otel/propagation".TraceContext` type no longer injects empty `tracestate` values. (#2108)
+- Use `6831` as default Jaeger agent port instead of `6832`. (#2131)
+
+## [Experimental Metrics v0.22.0] - 2021-07-19
+
+### Added
+
+- Adds HTTP support for OTLP metrics exporter. (#2022)
+
+### Removed
+
+- Removed the deprecated package `go.opentelemetry.io/otel/exporters/metric/prometheus`. (#2020)
+
+## [1.0.0-RC1] / 0.21.0 - 2021-06-18
+
+With this release we are introducing a split in module versions.  The tracing API and SDK are entering the `v1.0.0` Release Candidate phase with `v1.0.0-RC1`
+while the experimental metrics API and SDK continue with `v0.x` releases at `v0.21.0`.  Modules at major version 1 or greater will not depend on modules
+with major version 0.
+
+### Added
+
+- Adds `otlpgrpc.WithRetry`option for configuring the retry policy for transient errors on the otlp/gRPC exporter. (#1832)
+  - The following status codes are defined as transient errors:
+      | gRPC Status Code | Description |
+      | ---------------- | ----------- |
+      | 1  | Cancelled |
+      | 4  | Deadline Exceeded |
+      | 8  | Resource Exhausted |
+      | 10 | Aborted |
+      | 10 | Out of Range |
+      | 14 | Unavailable |
+      | 15 | Data Loss |
+- Added `Status` type to the `go.opentelemetry.io/otel/sdk/trace` package to represent the status of a span. (#1874)
+- Added `SpanStub` type and its associated functions to the `go.opentelemetry.io/otel/sdk/trace/tracetest` package.
+  This type can be used as a testing replacement for the `SpanSnapshot` that was removed from the `go.opentelemetry.io/otel/sdk/trace` package. (#1873)
+- Adds support for scheme in `OTEL_EXPORTER_OTLP_ENDPOINT` according to the spec. (#1886)
+- Adds `trace.WithSchemaURL` option for configuring the tracer with a Schema URL. (#1889)
+- Added an example of using OpenTelemetry Go as a trace context forwarder. (#1912)
+- `ParseTraceState` is added to the `go.opentelemetry.io/otel/trace` package.
+  It can be used to decode a `TraceState` from a `tracestate` header string value. (#1937)
+- Added `Len` method to the `TraceState` type in the `go.opentelemetry.io/otel/trace` package.
+  This method returns the number of list-members the `TraceState` holds. (#1937)
+- Creates package `go.opentelemetry.io/otel/exporters/otlp/otlptrace` that defines a trace exporter that uses a `otlptrace.Client` to send data.
+  Creates package `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` implementing a gRPC `otlptrace.Client` and offers convenience functions, `NewExportPipeline` and `InstallNewPipeline`, to setup and install a `otlptrace.Exporter` in tracing .(#1922)
+- Added `Baggage`, `Member`, and `Property` types to the `go.opentelemetry.io/otel/baggage` package along with their related functions. (#1967)
+- Added `ContextWithBaggage`, `ContextWithoutBaggage`, and `FromContext` functions to the `go.opentelemetry.io/otel/baggage` package.
+  These functions replace the `Set`, `Value`, `ContextWithValue`, `ContextWithoutValue`, and `ContextWithEmpty` functions from that package and directly work with the new `Baggage` type. (#1967)
+- The `OTEL_SERVICE_NAME` environment variable is the preferred source for `service.name`, used by the environment resource detector if a service name is present both there and in `OTEL_RESOURCE_ATTRIBUTES`. (#1969)
+- Creates package `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` implementing an HTTP `otlptrace.Client` and offers convenience functions, `NewExportPipeline` and `InstallNewPipeline`, to setup and install a `otlptrace.Exporter` in tracing. (#1963)
+- Changes `go.opentelemetry.io/otel/sdk/resource.NewWithAttributes` to require a schema URL. The old function is still available as `resource.NewSchemaless`. This is a breaking change. (#1938)
+- Several builtin resource detectors now correctly populate the schema URL. (#1938)
+- Creates package `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` that defines a metrics exporter that uses a `otlpmetric.Client` to send data.
+- Creates package `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` implementing a gRPC `otlpmetric.Client` and offers convenience functions, `New` and `NewUnstarted`, to create an `otlpmetric.Exporter`.(#1991)
+- Added `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` exporter. (#2005)
+- Added `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` exporter. (#2005)
+- Added a `TracerProvider()` method to the `"go.opentelemetry.io/otel/trace".Span` interface. This can be used to obtain a `TracerProvider` from a given span that utilizes the same trace processing pipeline.  (#2009)
+
+### Changed
+
+- Make `NewSplitDriver` from `go.opentelemetry.io/otel/exporters/otlp` take variadic arguments instead of a `SplitConfig` item.
+  `NewSplitDriver` now automatically implements an internal `noopDriver` for `SplitConfig` fields that are not initialized. (#1798)
+- `resource.New()` now creates a Resource without builtin detectors. Previous behavior is now achieved by using `WithBuiltinDetectors` Option. (#1810)
+- Move the `Event` type from the `go.opentelemetry.io/otel` package to the `go.opentelemetry.io/otel/sdk/trace` package. (#1846)
+- CI builds validate against last two versions of Go, dropping 1.14 and adding 1.16. (#1865)
+- BatchSpanProcessor now report export failures when calling `ForceFlush()` method. (#1860)
+- `Set.Encoded(Encoder)` no longer caches the result of an encoding. (#1855)
+- Renamed `CloudZoneKey` to `CloudAvailabilityZoneKey` in Resource semantic conventions according to spec. (#1871)
+- The `StatusCode` and `StatusMessage` methods of the `ReadOnlySpan` interface and the `Span` produced by the `go.opentelemetry.io/otel/sdk/trace` package have been replaced with a single `Status` method.
+  This method returns the status of a span using the new `Status` type. (#1874)
+- Updated `ExportSpans` method of the`SpanExporter` interface type to accept `ReadOnlySpan`s instead of the removed `SpanSnapshot`.
+  This brings the export interface into compliance with the specification in that it now accepts an explicitly immutable type instead of just an implied one. (#1873)
+- Unembed `SpanContext` in `Link`. (#1877)
+- Generate Semantic conventions from the specification YAML. (#1891)
+- Spans created by the global `Tracer` obtained from `go.opentelemetry.io/otel`, prior to a functioning `TracerProvider` being set, now propagate the span context from their parent if one exists. (#1901)
+- The `"go.opentelemetry.io/otel".Tracer` function now accepts tracer options. (#1902)
+- Move the `go.opentelemetry.io/otel/unit` package to `go.opentelemetry.io/otel/metric/unit`. (#1903)
+- Changed `go.opentelemetry.io/otel/trace.TracerConfig` to conform to the [Contributing guidelines](CONTRIBUTING.md#config.) (#1921)
+- Changed `go.opentelemetry.io/otel/trace.SpanConfig` to conform to the [Contributing guidelines](CONTRIBUTING.md#config). (#1921)
+- Changed `span.End()` now only accepts Options that are allowed at `End()`. (#1921)
+- Changed `go.opentelemetry.io/otel/metric.InstrumentConfig` to conform to the [Contributing guidelines](CONTRIBUTING.md#config). (#1921)
+- Changed `go.opentelemetry.io/otel/metric.MeterConfig` to conform to the [Contributing guidelines](CONTRIBUTING.md#config). (#1921)
+- Refactored option types according to the contribution style guide. (#1882)
+- Move the `go.opentelemetry.io/otel/trace.TraceStateFromKeyValues` function to the `go.opentelemetry.io/otel/oteltest` package.
+  This function is preserved for testing purposes where it may be useful to create a `TraceState` from `attribute.KeyValue`s, but it is not intended for production use.
+  The new `ParseTraceState` function should be used to create a `TraceState`. (#1931)
+- Updated `MarshalJSON` method of the `go.opentelemetry.io/otel/trace.TraceState` type to marshal the type into the string representation of the `TraceState`. (#1931)
+- The `TraceState.Delete` method from the `go.opentelemetry.io/otel/trace` package no longer returns an error in addition to a `TraceState`. (#1931)
+- Updated `Get` method of the `TraceState` type from the `go.opentelemetry.io/otel/trace` package to accept a `string` instead of an `attribute.Key` type. (#1931)
+- Updated `Insert` method of the `TraceState` type from the `go.opentelemetry.io/otel/trace` package to accept a pair of `string`s instead of an `attribute.KeyValue` type. (#1931)
+- Updated `Delete` method of the `TraceState` type from the `go.opentelemetry.io/otel/trace` package to accept a `string` instead of an `attribute.Key` type. (#1931)
+- Renamed `NewExporter` to `New` in the `go.opentelemetry.io/otel/exporters/stdout` package. (#1985)
+- Renamed `NewExporter` to `New` in the `go.opentelemetry.io/otel/exporters/metric/prometheus` package. (#1985)
+- Renamed `NewExporter` to `New` in the `go.opentelemetry.io/otel/exporters/trace/jaeger` package. (#1985)
+- Renamed `NewExporter` to `New` in the `go.opentelemetry.io/otel/exporters/trace/zipkin` package. (#1985)
+- Renamed `NewExporter` to `New` in the `go.opentelemetry.io/otel/exporters/otlp` package. (#1985)
+- Renamed `NewUnstartedExporter` to `NewUnstarted` in the `go.opentelemetry.io/otel/exporters/otlp` package. (#1985)
+- The `go.opentelemetry.io/otel/semconv` package has been moved to `go.opentelemetry.io/otel/semconv/v1.4.0` to allow for multiple [telemetry schema](https://github.com/open-telemetry/oteps/blob/main/text/0152-telemetry-schemas.md) versions to be used concurrently. (#1987)
+- Metrics test helpers in `go.opentelemetry.io/otel/oteltest` have been moved to `go.opentelemetry.io/otel/metric/metrictest`. (#1988)
+
+### Deprecated
+
+- The `go.opentelemetry.io/otel/exporters/metric/prometheus` is deprecated, use `go.opentelemetry.io/otel/exporters/prometheus` instead. (#1993)
+- The `go.opentelemetry.io/otel/exporters/trace/jaeger` is deprecated, use `go.opentelemetry.io/otel/exporters/jaeger` instead. (#1993)
+- The `go.opentelemetry.io/otel/exporters/trace/zipkin` is deprecated, use `go.opentelemetry.io/otel/exporters/zipkin` instead. (#1993)
+
+### Removed
+
+- Removed `resource.WithoutBuiltin()`. Use `resource.New()`. (#1810)
+- Unexported types `resource.FromEnv`, `resource.Host`, and `resource.TelemetrySDK`, Use the corresponding `With*()` to use individually. (#1810)
+- Removed the `Tracer` and `IsRecording` method from the `ReadOnlySpan` in the `go.opentelemetry.io/otel/sdk/trace`.
+  The `Tracer` method is not a required to be included in this interface and given the mutable nature of the tracer that is associated with a span, this method is not appropriate.
+  The `IsRecording` method returns if the span is recording or not.
+  A read-only span value does not need to know if updates to it will be recorded or not.
+  By definition, it cannot be updated so there is no point in communicating if an update is recorded. (#1873)
+- Removed the `SpanSnapshot` type from the `go.opentelemetry.io/otel/sdk/trace` package.
+  The use of this type has been replaced with the use of the explicitly immutable `ReadOnlySpan` type.
+  When a concrete representation of a read-only span is needed for testing, the newly added `SpanStub` in the `go.opentelemetry.io/otel/sdk/trace/tracetest` package should be used. (#1873)
+- Removed the `Tracer` method from the `Span` interface in the `go.opentelemetry.io/otel/trace` package.
+  Using the same tracer that created a span introduces the error where an instrumentation library's `Tracer` is used by other code instead of their own.
+  The `"go.opentelemetry.io/otel".Tracer` function or a `TracerProvider` should be used to acquire a library specific `Tracer` instead. (#1900)
+  - The `TracerProvider()` method on the `Span` interface may also be used to obtain a `TracerProvider` using the same trace processing pipeline. (#2009)
+- The `http.url` attribute generated by `HTTPClientAttributesFromHTTPRequest` will no longer include username or password information. (#1919)
+- Removed `IsEmpty` method of the `TraceState` type in the `go.opentelemetry.io/otel/trace` package in favor of using the added `TraceState.Len` method. (#1931)
+- Removed `Set`, `Value`, `ContextWithValue`, `ContextWithoutValue`, and `ContextWithEmpty` functions in the `go.opentelemetry.io/otel/baggage` package.
+  Handling of baggage is now done using the added `Baggage` type and related context functions (`ContextWithBaggage`, `ContextWithoutBaggage`, and `FromContext`) in that package. (#1967)
+- The `InstallNewPipeline` and `NewExportPipeline` creation functions in all the exporters (prometheus, otlp, stdout, jaeger, and zipkin) have been removed.
+  These functions were deemed premature attempts to provide convenience that did not achieve this aim. (#1985)
+- The `go.opentelemetry.io/otel/exporters/otlp` exporter has been removed.  Use `go.opentelemetry.io/otel/exporters/otlp/otlptrace` instead. (#1990)
+- The `go.opentelemetry.io/otel/exporters/stdout` exporter has been removed.  Use `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` or `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` instead. (#2005)
+
+### Fixed
+
+- Only report errors from the `"go.opentelemetry.io/otel/sdk/resource".Environment` function when they are not `nil`. (#1850, #1851)
+- The `Shutdown` method of the simple `SpanProcessor` in the `go.opentelemetry.io/otel/sdk/trace` package now honors the context deadline or cancellation. (#1616, #1856)
+- BatchSpanProcessor now drops span batches that failed to be exported. (#1860)
+- Use `http://localhost:14268/api/traces` as default Jaeger collector endpoint instead of `http://localhost:14250`. (#1898)
+- Allow trailing and leading whitespace in the parsing of a `tracestate` header. (#1931)
+- Add logic to determine if the channel is closed to fix Jaeger exporter test panic with close closed channel. (#1870, #1973)
+- Avoid transport security when OTLP endpoint is a Unix socket. (#2001)
+
+### Security
+
+## [0.20.0] - 2021-04-23
+
+### Added
+
+- The OTLP exporter now has two new convenience functions, `NewExportPipeline` and `InstallNewPipeline`, setup and install the exporter in tracing and metrics pipelines. (#1373)
+- Adds semantic conventions for exceptions. (#1492)
+- Added Jaeger Environment variables: `OTEL_EXPORTER_JAEGER_AGENT_HOST`, `OTEL_EXPORTER_JAEGER_AGENT_PORT`
+  These environment variables can be used to override Jaeger agent hostname and port (#1752)
+- Option `ExportTimeout` was added to batch span processor. (#1755)
+- `trace.TraceFlags` is now a defined type over `byte` and `WithSampled(bool) TraceFlags` and `IsSampled() bool` methods have been added to it. (#1770)
+- The `Event` and `Link` struct types from the `go.opentelemetry.io/otel` package now include a `DroppedAttributeCount` field to record the number of attributes that were not recorded due to configured limits being reached. (#1771)
+- The Jaeger exporter now reports dropped attributes for a Span event in the exported log. (#1771)
+- Adds test to check BatchSpanProcessor ignores `OnEnd` and `ForceFlush` post `Shutdown`. (#1772)
+- Extract resource attributes from the `OTEL_RESOURCE_ATTRIBUTES` environment variable and merge them with the `resource.Default` resource as well as resources provided to the `TracerProvider` and metric `Controller`. (#1785)
+- Added `WithOSType` resource configuration option to set OS (Operating System) type resource attribute (`os.type`). (#1788)
+- Added `WithProcess*` resource configuration options to set Process resource attributes. (#1788)
+  - `process.pid`
+  - `process.executable.name`
+  - `process.executable.path`
+  - `process.command_args`
+  - `process.owner`
+  - `process.runtime.name`
+  - `process.runtime.version`
+  - `process.runtime.description`
+- Adds `k8s.node.name` and `k8s.node.uid` attribute keys to the `semconv` package. (#1789)
+- Added support for configuring OTLP/HTTP and OTLP/gRPC Endpoints, TLS Certificates, Headers, Compression and Timeout via Environment Variables. (#1758, #1769 and #1811)
+  - `OTEL_EXPORTER_OTLP_ENDPOINT`
+  - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`
+  - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`
+  - `OTEL_EXPORTER_OTLP_HEADERS`
+  - `OTEL_EXPORTER_OTLP_TRACES_HEADERS`
+  - `OTEL_EXPORTER_OTLP_METRICS_HEADERS`
+  - `OTEL_EXPORTER_OTLP_COMPRESSION`
+  - `OTEL_EXPORTER_OTLP_TRACES_COMPRESSION`
+  - `OTEL_EXPORTER_OTLP_METRICS_COMPRESSION`
+  - `OTEL_EXPORTER_OTLP_TIMEOUT`
+  - `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT`
+  - `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT`
+  - `OTEL_EXPORTER_OTLP_CERTIFICATE`
+  - `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE`
+  - `OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE`
+- Adds `otlpgrpc.WithTimeout` option for configuring timeout to the otlp/gRPC exporter. (#1821)
+- Adds `jaeger.WithMaxPacketSize` option for configuring maximum UDP packet size used when connecting to the Jaeger agent. (#1853)
+
+### Fixed
+
+- The `Span.IsRecording` implementation from `go.opentelemetry.io/otel/sdk/trace` always returns false when not being sampled. (#1750)
+- The Jaeger exporter now correctly sets tags for the Span status code and message.
+  This means it uses the correct tag keys (`"otel.status_code"`, `"otel.status_description"`) and does not set the status message as a tag unless it is set on the span. (#1761)
+- The Jaeger exporter now correctly records Span event's names using the `"event"` key for a tag.
+  Additionally, this tag is overridden, as specified in the OTel specification, if the event contains an attribute with that key. (#1768)
+- Zipkin Exporter: Ensure mapping between OTel and Zipkin span data complies with the specification. (#1688)
+- Fixed typo for default service name in Jaeger Exporter. (#1797)
+- Fix flaky OTLP for the reconnnection of the client connection. (#1527, #1814)
+- Fix Jaeger exporter dropping of span batches that exceed the UDP packet size limit.
+  Instead, the exporter now splits the batch into smaller sendable batches. (#1828)
+
+### Changed
+
+- Span `RecordError` now records an `exception` event to comply with the semantic convention specification. (#1492)
+- Jaeger exporter was updated to use thrift v0.14.1. (#1712)
+- Migrate from using internally built and maintained version of the OTLP to the one hosted at `go.opentelemetry.io/proto/otlp`. (#1713)
+- Migrate from using `github.com/gogo/protobuf` to `google.golang.org/protobuf` to match `go.opentelemetry.io/proto/otlp`. (#1713)
+- The storage of a local or remote Span in a `context.Context` using its SpanContext is unified to store just the current Span.
+  The Span's SpanContext can now self-identify as being remote or not.
+  This means that `"go.opentelemetry.io/otel/trace".ContextWithRemoteSpanContext` will now overwrite any existing current Span, not just existing remote Spans, and make it the current Span in a `context.Context`. (#1731)
+- Improve OTLP/gRPC exporter connection errors. (#1737)
+- Information about a parent span context in a `"go.opentelemetry.io/otel/export/trace".SpanSnapshot` is unified in a new `Parent` field.
+  The existing `ParentSpanID` and `HasRemoteParent` fields are removed in favor of this. (#1748)
+- The `ParentContext` field of the `"go.opentelemetry.io/otel/sdk/trace".SamplingParameters` is updated to hold a `context.Context` containing the parent span.
+  This changes it to make `SamplingParameters` conform with the OpenTelemetry specification. (#1749)
+- Updated Jaeger Environment Variables: `JAEGER_ENDPOINT`, `JAEGER_USER`, `JAEGER_PASSWORD`
+  to `OTEL_EXPORTER_JAEGER_ENDPOINT`, `OTEL_EXPORTER_JAEGER_USER`, `OTEL_EXPORTER_JAEGER_PASSWORD` in compliance with OTel specification. (#1752)
+- Modify `BatchSpanProcessor.ForceFlush` to abort after timeout/cancellation. (#1757)
+- The `DroppedAttributeCount` field of the `Span` in the `go.opentelemetry.io/otel` package now only represents the number of attributes dropped for the span itself.
+  It no longer is a conglomerate of itself, events, and link attributes that have been dropped. (#1771)
+- Make `ExportSpans` in Jaeger Exporter honor context deadline. (#1773)
+- Modify Zipkin Exporter default service name, use default resource's serviceName instead of empty. (#1777)
+- The `go.opentelemetry.io/otel/sdk/export/trace` package is merged into the `go.opentelemetry.io/otel/sdk/trace` package. (#1778)
+- The prometheus.InstallNewPipeline example is moved from comment to example test (#1796)
+- The convenience functions for the stdout exporter have been updated to return the `TracerProvider` implementation and enable the shutdown of the exporter. (#1800)
+- Replace the flush function returned from the Jaeger exporter's convenience creation functions (`InstallNewPipeline` and `NewExportPipeline`) with the `TracerProvider` implementation they create.
+  This enables the caller to shutdown and flush using the related `TracerProvider` methods. (#1822)
+- Updated the Jaeger exporter to have a default endpoint, `http://localhost:14250`, for the collector. (#1824)
+- Changed the function `WithCollectorEndpoint` in the Jaeger exporter to no longer accept an endpoint as an argument.
+  The endpoint can be passed with the `CollectorEndpointOption` using the `WithEndpoint` function or by setting the `OTEL_EXPORTER_JAEGER_ENDPOINT` environment variable value appropriately. (#1824)
+- The Jaeger exporter no longer batches exported spans itself, instead it relies on the SDK's `BatchSpanProcessor` for this functionality. (#1830)
+- The Jaeger exporter creation functions (`NewRawExporter`, `NewExportPipeline`, and `InstallNewPipeline`) no longer accept the removed `Option` type as a variadic argument. (#1830)
+
+### Removed
+
+- Removed Jaeger Environment variables: `JAEGER_SERVICE_NAME`, `JAEGER_DISABLED`, `JAEGER_TAGS`
+  These environment variables will no longer be used to override values of the Jaeger exporter (#1752)
+- No longer set the links for a `Span` in `go.opentelemetry.io/otel/sdk/trace` that is configured to be a new root.
+  This is unspecified behavior that the OpenTelemetry community plans to standardize in the future.
+  To prevent backwards incompatible changes when it is specified, these links are removed. (#1726)
+- Setting error status while recording error with Span from oteltest package. (#1729)
+- The concept of a remote and local Span stored in a context is unified to just the current Span.
+  Because of this `"go.opentelemetry.io/otel/trace".RemoteSpanContextFromContext` is removed as it is no longer needed.
+  Instead, `"go.opentelemetry.io/otel/trace".SpanContextFromContex` can be used to return the current Span.
+  If needed, that Span's `SpanContext.IsRemote()` can then be used to determine if it is remote or not. (#1731)
+- The `HasRemoteParent` field of the `"go.opentelemetry.io/otel/sdk/trace".SamplingParameters` is removed.
+  This field is redundant to the information returned from the `Remote` method of the `SpanContext` held in the `ParentContext` field. (#1749)
+- The `trace.FlagsDebug` and `trace.FlagsDeferred` constants have been removed and will be localized to the B3 propagator. (#1770)
+- Remove `Process` configuration, `WithProcessFromEnv` and `ProcessFromEnv`, and type from the Jaeger exporter package.
+  The information that could be configured in the `Process` struct should be configured in a `Resource` instead. (#1776, #1804)
+- Remove the `WithDisabled` option from the Jaeger exporter.
+  To disable the exporter unregister it from the `TracerProvider` or use a no-operation `TracerProvider`. (#1806)
+- Removed the functions `CollectorEndpointFromEnv` and `WithCollectorEndpointOptionFromEnv` from the Jaeger exporter.
+  These functions for retrieving specific environment variable values are redundant of other internal functions and
+  are not intended for end user use. (#1824)
+- Removed the Jaeger exporter `WithSDKOptions` `Option`.
+  This option was used to set SDK options for the exporter creation convenience functions.
+  These functions are provided as a way to easily setup or install the exporter with what are deemed reasonable SDK settings for common use cases.
+  If the SDK needs to be configured differently, the `NewRawExporter` function and direct setup of the SDK with the desired settings should be used. (#1825)
+- The `WithBufferMaxCount` and `WithBatchMaxCount` `Option`s from the Jaeger exporter are removed.
+  The exporter no longer batches exports, instead relying on the SDK's `BatchSpanProcessor` for this functionality. (#1830)
+- The Jaeger exporter `Option` type is removed.
+  The type is no longer used by the exporter to configure anything.
+  All the previous configurations these options provided were duplicates of SDK configuration.
+  They have been removed in favor of using the SDK configuration and focuses the exporter configuration to be only about the endpoints it will send telemetry to. (#1830)
+
+## [0.19.0] - 2021-03-18
+
+### Added
+
+- Added `Marshaler` config option to `otlphttp` to enable otlp over json or protobufs. (#1586)
+- A `ForceFlush` method to the `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` to flush all registered `SpanProcessor`s. (#1608)
+- Added `WithSampler` and `WithSpanLimits` to tracer provider. (#1633, #1702)
+- `"go.opentelemetry.io/otel/trace".SpanContext` now has a `remote` property, and `IsRemote()` predicate, that is true when the `SpanContext` has been extracted from remote context data. (#1701)
+- A `Valid` method to the `"go.opentelemetry.io/otel/attribute".KeyValue` type. (#1703)
+
+### Changed
+
+- `trace.SpanContext` is now immutable and has no exported fields. (#1573)
+  - `trace.NewSpanContext()` can be used in conjunction with the `trace.SpanContextConfig` struct to initialize a new `SpanContext` where all values are known.
+- Update the `ForceFlush` method signature to the `"go.opentelemetry.io/otel/sdk/trace".SpanProcessor` to accept a `context.Context` and return an error. (#1608)
+- Update the `Shutdown` method to the `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` return an error on shutdown failure. (#1608)
+- The SimpleSpanProcessor will now shut down the enclosed `SpanExporter` and gracefully ignore subsequent calls to `OnEnd` after `Shutdown` is called. (#1612)
+- `"go.opentelemetry.io/sdk/metric/controller.basic".WithPusher` is replaced with `WithExporter` to provide consistent naming across project. (#1656)
+- Added non-empty string check for trace `Attribute` keys. (#1659)
+- Add `description` to SpanStatus only when `StatusCode` is set to error. (#1662)
+- Jaeger exporter falls back to `resource.Default`'s `service.name` if the exported Span does not have one. (#1673)
+- Jaeger exporter populates Jaeger's Span Process from Resource. (#1673)
+- Renamed the `LabelSet` method of `"go.opentelemetry.io/otel/sdk/resource".Resource` to `Set`. (#1692)
+- Changed `WithSDK` to `WithSDKOptions` to accept variadic arguments of `TracerProviderOption` type in `go.opentelemetry.io/otel/exporters/trace/jaeger` package. (#1693)
+- Changed `WithSDK` to `WithSDKOptions` to accept variadic arguments of `TracerProviderOption` type in `go.opentelemetry.io/otel/exporters/trace/zipkin` package. (#1693)
+
+### Removed
+
+- Removed `serviceName` parameter from Zipkin exporter and uses resource instead. (#1549)
+- Removed `WithConfig` from tracer provider to avoid overriding configuration. (#1633)
+- Removed the exported `SimpleSpanProcessor` and `BatchSpanProcessor` structs.
+   These are now returned as a SpanProcessor interface from their respective constructors. (#1638)
+- Removed `WithRecord()` from `trace.SpanOption` when creating a span. (#1660)
+- Removed setting status to `Error` while recording an error as a span event in `RecordError`. (#1663)
+- Removed `jaeger.WithProcess` configuration option. (#1673)
+- Removed `ApplyConfig` method from `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` and the now unneeded `Config` struct. (#1693)
+
+### Fixed
+
+- Jaeger Exporter: Ensure mapping between OTEL and Jaeger span data complies with the specification. (#1626)
+- `SamplingResult.TraceState` is correctly propagated to a newly created span's `SpanContext`. (#1655)
+- The `otel-collector` example now correctly flushes metric events prior to shutting down the exporter. (#1678)
+- Do not set span status message in `SpanStatusFromHTTPStatusCode` if it can be inferred from `http.status_code`. (#1681)
+- Synchronization issues in global trace delegate implementation. (#1686)
+- Reduced excess memory usage by global `TracerProvider`. (#1687)
+
+## [0.18.0] - 2021-03-03
+
+### Added
+
+- Added `resource.Default()` for use with meter and tracer providers. (#1507)
+- `AttributePerEventCountLimit` and `AttributePerLinkCountLimit` for `SpanLimits`. (#1535)
+- Added `Keys()` method to `propagation.TextMapCarrier` and `propagation.HeaderCarrier` to adapt `http.Header` to this interface. (#1544)
+- Added `code` attributes to `go.opentelemetry.io/otel/semconv` package. (#1558)
+- Compatibility testing suite in the CI system for the following systems. (#1567)
+   | OS      | Go Version | Architecture |
+   | ------- | ---------- | ------------ |
+   | Ubuntu  | 1.15       | amd64        |
+   | Ubuntu  | 1.14       | amd64        |
+   | Ubuntu  | 1.15       | 386          |
+   | Ubuntu  | 1.14       | 386          |
+   | MacOS   | 1.15       | amd64        |
+   | MacOS   | 1.14       | amd64        |
+   | Windows | 1.15       | amd64        |
+   | Windows | 1.14       | amd64        |
+   | Windows | 1.15       | 386          |
+   | Windows | 1.14       | 386          |
+
+### Changed
+
+- Replaced interface `oteltest.SpanRecorder` with its existing implementation
+  `StandardSpanRecorder`. (#1542)
+- Default span limit values to 128. (#1535)
+- Rename `MaxEventsPerSpan`, `MaxAttributesPerSpan` and `MaxLinksPerSpan` to `EventCountLimit`, `AttributeCountLimit` and `LinkCountLimit`, and move these fields into `SpanLimits`. (#1535)
+- Renamed the `otel/label` package to `otel/attribute`. (#1541)
+- Vendor the Jaeger exporter's dependency on Apache Thrift. (#1551)
+- Parallelize the CI linting and testing. (#1567)
+- Stagger timestamps in exact aggregator tests. (#1569)
+- Changed all examples to use `WithBatchTimeout(5 * time.Second)` rather than `WithBatchTimeout(5)`. (#1621)
+- Prevent end-users from implementing some interfaces (#1575)
+
+  ```
+      "otel/exporters/otlp/otlphttp".Option
+      "otel/exporters/stdout".Option
+      "otel/oteltest".Option
+      "otel/trace".TracerOption
+      "otel/trace".SpanOption
+      "otel/trace".EventOption
+      "otel/trace".LifeCycleOption
+      "otel/trace".InstrumentationOption
+      "otel/sdk/resource".Option
+      "otel/sdk/trace".ParentBasedSamplerOption
+      "otel/sdk/trace".ReadOnlySpan
+      "otel/sdk/trace".ReadWriteSpan
+  ```
+
+### Removed
+
+- Removed attempt to resample spans upon changing the span name with `span.SetName()`. (#1545)
+- The `test-benchmark` is no longer a dependency of the `precommit` make target. (#1567)
+- Removed the `test-386` make target.
+   This was replaced with a full compatibility testing suite (i.e. multi OS/arch) in the CI system. (#1567)
+
+### Fixed
+
+- The sequential timing check of timestamps in the stdout exporter are now setup explicitly to be sequential (#1571). (#1572)
+- Windows build of Jaeger tests now compiles with OS specific functions (#1576). (#1577)
+- The sequential timing check of timestamps of go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue are now setup explicitly to be sequential (#1578). (#1579)
+- Validate tracestate header keys with vendors according to the W3C TraceContext specification (#1475). (#1581)
+- The OTLP exporter includes related labels for translations of a GaugeArray (#1563). (#1570)
+
+## [0.17.0] - 2021-02-12
+
+### Changed
+
+- Rename project default branch from `master` to `main`. (#1505)
+- Reverse order in which `Resource` attributes are merged, per change in spec. (#1501)
+- Add tooling to maintain "replace" directives in go.mod files automatically. (#1528)
+- Create new modules: otel/metric, otel/trace, otel/oteltest, otel/sdk/export/metric, otel/sdk/metric (#1528)
+- Move metric-related public global APIs from otel to otel/metric/global. (#1528)
+
+## Fixed
+
+- Fixed otlpgrpc reconnection issue.
+- The example code in the README.md of `go.opentelemetry.io/otel/exporters/otlp` is moved to a compiled example test and used the new `WithAddress` instead of `WithEndpoint`. (#1513)
+- The otel-collector example now uses the default OTLP receiver port of the collector.
+
+## [0.16.0] - 2021-01-13
+
+### Added
+
+- Add the `ReadOnlySpan` and `ReadWriteSpan` interfaces to provide better control for accessing span data. (#1360)
+- `NewGRPCDriver` function returns a `ProtocolDriver` that maintains a single gRPC connection to the collector. (#1369)
+- Added documentation about the project's versioning policy. (#1388)
+- Added `NewSplitDriver` for OTLP exporter that allows sending traces and metrics to different endpoints. (#1418)
+- Added codeql workflow to GitHub Actions (#1428)
+- Added Gosec workflow to GitHub Actions (#1429)
+- Add new HTTP driver for OTLP exporter in `exporters/otlp/otlphttp`. Currently it only supports the binary protobuf payloads. (#1420)
+- Add an OpenCensus exporter bridge. (#1444)
+
+### Changed
+
+- Rename `internal/testing` to `internal/internaltest`. (#1449)
+- Rename `export.SpanData` to `export.SpanSnapshot` and use it only for exporting spans. (#1360)
+- Store the parent's full `SpanContext` rather than just its span ID in the `span` struct. (#1360)
+- Improve span duration accuracy. (#1360)
+- Migrated CI/CD from CircleCI to GitHub Actions (#1382)
+- Remove duplicate checkout from GitHub Actions workflow (#1407)
+- Metric `array` aggregator renamed `exact` to match its `aggregation.Kind` (#1412)
+- Metric `exact` aggregator includes per-point timestamps (#1412)
+- Metric stdout exporter uses MinMaxSumCount aggregator for ValueRecorder instruments (#1412)
+- `NewExporter` from `exporters/otlp` now takes a `ProtocolDriver` as a parameter. (#1369)
+- Many OTLP Exporter options became gRPC ProtocolDriver options. (#1369)
+- Unify endpoint API that related to OTel exporter. (#1401)
+- Optimize metric histogram aggregator to re-use its slice of buckets. (#1435)
+- Metric aggregator Count() and histogram Bucket.Counts are consistently `uint64`. (1430)
+- Histogram aggregator accepts functional options, uses default boundaries if none given. (#1434)
+- `SamplingResult` now passed a `Tracestate` from the parent `SpanContext` (#1432)
+- Moved gRPC driver for OTLP exporter to `exporters/otlp/otlpgrpc`. (#1420)
+- The `TraceContext` propagator now correctly propagates `TraceState` through the `SpanContext`. (#1447)
+- Metric Push and Pull Controller components are combined into a single "basic" Controller:
+  - `WithExporter()` and `Start()` to configure Push behavior
+  - `Start()` is optional; use `Collect()` and `ForEach()` for Pull behavior
+  - `Start()` and `Stop()` accept Context. (#1378)
+- The `Event` type is moved from the `otel/sdk/export/trace` package to the `otel/trace` API package. (#1452)
+
+### Removed
+
+- Remove `errUninitializedSpan` as its only usage is now obsolete. (#1360)
+- Remove Metric export functionality related to quantiles and summary data points: this is not specified (#1412)
+- Remove DDSketch metric aggregator; our intention is to re-introduce this as an option of the histogram aggregator after [new OTLP histogram data types](https://github.com/open-telemetry/opentelemetry-proto/pull/226) are released (#1412)
+
+### Fixed
+
+- `BatchSpanProcessor.Shutdown()` will now shutdown underlying `export.SpanExporter`. (#1443)
+
+## [0.15.0] - 2020-12-10
+
+### Added
+
+- The `WithIDGenerator` `TracerProviderOption` is added to the `go.opentelemetry.io/otel/trace` package to configure an `IDGenerator` for the `TracerProvider`. (#1363)
+
+### Changed
+
+- The Zipkin exporter now uses the Span status code to determine. (#1328)
+- `NewExporter` and `Start` functions in `go.opentelemetry.io/otel/exporters/otlp` now receive `context.Context` as a first parameter. (#1357)
+- Move the OpenCensus example into `example` directory. (#1359)
+- Moved the SDK's `internal.IDGenerator` interface in to the `sdk/trace` package to enable support for externally-defined ID generators. (#1363)
+- Bump `github.com/google/go-cmp` from 0.5.3 to 0.5.4 (#1374)
+- Bump `github.com/golangci/golangci-lint` in `/internal/tools` (#1375)
+
+### Fixed
+
+- Metric SDK `SumObserver` and `UpDownSumObserver` instruments correctness fixes. (#1381)
+
+## [0.14.0] - 2020-11-19
+
+### Added
+
+- An `EventOption` and the related `NewEventConfig` function are added to the `go.opentelemetry.io/otel` package to configure Span events. (#1254)
+- A `TextMapPropagator` and associated `TextMapCarrier` are added to the `go.opentelemetry.io/otel/oteltest` package to test `TextMap` type propagators and their use. (#1259)
+- `SpanContextFromContext` returns `SpanContext` from context. (#1255)
+- `TraceState` has been added to `SpanContext`. (#1340)
+- `DeploymentEnvironmentKey` added to `go.opentelemetry.io/otel/semconv` package. (#1323)
+- Add an OpenCensus to OpenTelemetry tracing bridge. (#1305)
+- Add a parent context argument to `SpanProcessor.OnStart` to follow the specification. (#1333)
+- Add missing tests for `sdk/trace/attributes_map.go`. (#1337)
+
+### Changed
+
+- Move the `go.opentelemetry.io/otel/api/trace` package into `go.opentelemetry.io/otel/trace` with the following changes. (#1229) (#1307)
+  - `ID` has been renamed to `TraceID`.
+  - `IDFromHex` has been renamed to `TraceIDFromHex`.
+  - `EmptySpanContext` is removed.
+- Move the `go.opentelemetry.io/otel/api/trace/tracetest` package into `go.opentelemetry.io/otel/oteltest`. (#1229)
+- OTLP Exporter updates:
+  - supports OTLP v0.6.0 (#1230, #1354)
+  - supports configurable aggregation temporality (default: Cumulative, optional: Stateless). (#1296)
+- The Sampler is now called on local child spans. (#1233)
+- The `Kind` type from the `go.opentelemetry.io/otel/api/metric` package was renamed to `InstrumentKind` to more specifically describe what it is and avoid semantic ambiguity. (#1240)
+- The `MetricKind` method of the `Descriptor` type in the `go.opentelemetry.io/otel/api/metric` package was renamed to `Descriptor.InstrumentKind`.
+   This matches the returned type and fixes misuse of the term metric. (#1240)
+- Move test harness from the `go.opentelemetry.io/otel/api/apitest` package into `go.opentelemetry.io/otel/oteltest`. (#1241)
+- Move the `go.opentelemetry.io/otel/api/metric/metrictest` package into `go.opentelemetry.io/oteltest` as part of #964. (#1252)
+- Move the `go.opentelemetry.io/otel/api/metric` package into `go.opentelemetry.io/otel/metric` as part of #1303. (#1321)
+- Move the `go.opentelemetry.io/otel/api/metric/registry` package into `go.opentelemetry.io/otel/metric/registry` as a part of #1303. (#1316)
+- Move the `Number` type (together with related functions) from `go.opentelemetry.io/otel/api/metric` package into `go.opentelemetry.io/otel/metric/number` as a part of #1303. (#1316)
+- The function signature of the Span `AddEvent` method in `go.opentelemetry.io/otel` is updated to no longer take an unused context and instead take a required name and a variable number of `EventOption`s. (#1254)
+- The function signature of the Span `RecordError` method in `go.opentelemetry.io/otel` is updated to no longer take an unused context and instead take a required error value and a variable number of `EventOption`s. (#1254)
+- Move the `go.opentelemetry.io/otel/api/global` package to `go.opentelemetry.io/otel`. (#1262) (#1330)
+- Move the `Version` function from `go.opentelemetry.io/otel/sdk` to `go.opentelemetry.io/otel`. (#1330)
+- Rename correlation context header from `"otcorrelations"` to `"baggage"` to match the OpenTelemetry specification. (#1267)
+- Fix `Code.UnmarshalJSON` to work with valid JSON only. (#1276)
+- The `resource.New()` method changes signature to support builtin attributes and functional options, including `telemetry.sdk.*` and
+  `host.name` semantic conventions; the former method is renamed `resource.NewWithAttributes`. (#1235)
+- The Prometheus exporter now exports non-monotonic counters (i.e. `UpDownCounter`s) as gauges. (#1210)
+- Correct the `Span.End` method documentation in the `otel` API to state updates are not allowed on a span after it has ended. (#1310)
+- Updated span collection limits for attribute, event and link counts to 1000 (#1318)
+- Renamed `semconv.HTTPUrlKey` to `semconv.HTTPURLKey`. (#1338)
+
+### Removed
+
+- The `ErrInvalidHexID`, `ErrInvalidTraceIDLength`, `ErrInvalidSpanIDLength`, `ErrInvalidSpanIDLength`, or `ErrNilSpanID` from the `go.opentelemetry.io/otel` package are unexported now. (#1243)
+- The `AddEventWithTimestamp` method on the `Span` interface in `go.opentelemetry.io/otel` is removed due to its redundancy.
+   It is replaced by using the `AddEvent` method with a `WithTimestamp` option. (#1254)
+- The `MockSpan` and `MockTracer` types are removed from `go.opentelemetry.io/otel/oteltest`.
+   `Tracer` and `Span` from the same module should be used in their place instead. (#1306)
+- `WorkerCount` option is removed from `go.opentelemetry.io/otel/exporters/otlp`. (#1350)
+- Remove the following labels types: INT32, UINT32, UINT64 and FLOAT32. (#1314)
+
+### Fixed
+
+- Rename `MergeItererator` to `MergeIterator` in the `go.opentelemetry.io/otel/label` package. (#1244)
+- The `go.opentelemetry.io/otel/api/global` packages global TextMapPropagator now delegates functionality to a globally set delegate for all previously returned propagators. (#1258)
+- Fix condition in `label.Any`. (#1299)
+- Fix global `TracerProvider` to pass options to its configured provider. (#1329)
+- Fix missing handler for `ExactKind` aggregator in OTLP metrics transformer (#1309)
+
+## [0.13.0] - 2020-10-08
+
+### Added
+
+- OTLP Metric exporter supports Histogram aggregation. (#1209)
+- The `Code` struct from the `go.opentelemetry.io/otel/codes` package now supports JSON marshaling and unmarshaling as well as implements the `Stringer` interface. (#1214)
+- A Baggage API to implement the OpenTelemetry specification. (#1217)
+- Add Shutdown method to sdk/trace/provider, shutdown processors in the order they were registered. (#1227)
+
+### Changed
+
+- Set default propagator to no-op propagator. (#1184)
+- The `HTTPSupplier`, `HTTPExtractor`, `HTTPInjector`, and `HTTPPropagator` from the `go.opentelemetry.io/otel/api/propagation` package were replaced with unified `TextMapCarrier` and `TextMapPropagator` in the `go.opentelemetry.io/otel/propagation` package. (#1212) (#1325)
+- The `New` function from the `go.opentelemetry.io/otel/api/propagation` package was replaced with `NewCompositeTextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212)
+- The status codes of the `go.opentelemetry.io/otel/codes` package have been updated to match the latest OpenTelemetry specification.
+   They now are `Unset`, `Error`, and `Ok`.
+   They no longer track the gRPC codes. (#1214)
+- The `StatusCode` field of the `SpanData` struct in the `go.opentelemetry.io/otel/sdk/export/trace` package now uses the codes package from this package instead of the gRPC project. (#1214)
+- Move the `go.opentelemetry.io/otel/api/baggage` package into `go.opentelemetry.io/otel/baggage`. (#1217) (#1325)
+- A `Shutdown` method of `SpanProcessor` and all its implementations receives a context and returns an error. (#1264)
+
+### Fixed
+
+- Copies of data from arrays and slices passed to `go.opentelemetry.io/otel/label.ArrayValue()` are now used in the returned `Value` instead of using the mutable data itself. (#1226)
+
+### Removed
+
+- The `ExtractHTTP` and `InjectHTTP` functions from the `go.opentelemetry.io/otel/api/propagation` package were removed. (#1212)
+- The `Propagators` interface from the `go.opentelemetry.io/otel/api/propagation` package was removed to conform to the OpenTelemetry specification.
+   The explicit `TextMapPropagator` type can be used in its place as this is the `Propagator` type the specification defines. (#1212)
+- The `SetAttribute` method of the `Span` from the `go.opentelemetry.io/otel/api/trace` package was removed given its redundancy with the `SetAttributes` method. (#1216)
+- The internal implementation of Baggage storage is removed in favor of using the new Baggage API functionality. (#1217)
+- Remove duplicate hostname key `HostHostNameKey` in Resource semantic conventions. (#1219)
+- Nested array/slice support has been removed. (#1226)
+
+## [0.12.0] - 2020-09-24
+
+### Added
+
+- A `SpanConfigure` function in `go.opentelemetry.io/otel/api/trace` to create a new `SpanConfig` from `SpanOption`s. (#1108)
+- In the `go.opentelemetry.io/otel/api/trace` package, `NewTracerConfig` was added to construct new `TracerConfig`s.
+   This addition was made to conform with our project option conventions. (#1155)
+- Instrumentation library information was added to the Zipkin exporter. (#1119)
+- The `SpanProcessor` interface now has a `ForceFlush()` method. (#1166)
+- More semantic conventions for k8s as resource attributes. (#1167)
+
+### Changed
+
+- Add reconnecting udp connection type to Jaeger exporter.
+   This change adds a new optional implementation of the udp conn interface used to detect changes to an agent's host dns record.
+   It then adopts the new destination address to ensure the exporter doesn't get stuck. This change was ported from jaegertracing/jaeger-client-go#520. (#1063)
+- Replace `StartOption` and `EndOption` in `go.opentelemetry.io/otel/api/trace` with `SpanOption`.
+   This change is matched by replacing the `StartConfig` and `EndConfig` with a unified `SpanConfig`. (#1108)
+- Replace the `LinkedTo` span option in `go.opentelemetry.io/otel/api/trace` with `WithLinks`.
+   This is be more consistent with our other option patterns, i.e. passing the item to be configured directly instead of its component parts, and provides a cleaner function signature. (#1108)
+- The `go.opentelemetry.io/otel/api/trace` `TracerOption` was changed to an interface to conform to project option conventions. (#1109)
+- Move the `B3` and `TraceContext` from within the `go.opentelemetry.io/otel/api/trace` package to their own `go.opentelemetry.io/otel/propagators` package.
+    This removal of the propagators is reflective of the OpenTelemetry specification for these propagators as well as cleans up the `go.opentelemetry.io/otel/api/trace` API. (#1118)
+- Rename Jaeger tags used for instrumentation library information to reflect changes in OpenTelemetry specification. (#1119)
+- Rename `ProbabilitySampler` to `TraceIDRatioBased` and change semantics to ignore parent span sampling status. (#1115)
+- Move `tools` package under `internal`. (#1141)
+- Move `go.opentelemetry.io/otel/api/correlation` package to `go.opentelemetry.io/otel/api/baggage`. (#1142)
+   The `correlation.CorrelationContext` propagator has been renamed `baggage.Baggage`.  Other exported functions and types are unchanged.
+- Rename `ParentOrElse` sampler to `ParentBased` and allow setting samplers depending on parent span. (#1153)
+- In the `go.opentelemetry.io/otel/api/trace` package, `SpanConfigure` was renamed to `NewSpanConfig`. (#1155)
+- Change `dependabot.yml` to add a `Skip Changelog` label to dependabot-sourced PRs. (#1161)
+- The [configuration style guide](https://github.com/open-telemetry/opentelemetry-go/blob/master/CONTRIBUTING.md#config) has been updated to
+   recommend the use of `newConfig()` instead of `configure()`. (#1163)
+- The `otlp.Config` type has been unexported and changed to `otlp.config`, along with its initializer. (#1163)
+- Ensure exported interface types include parameter names and update the
+   Style Guide to reflect this styling rule. (#1172)
+- Don't consider unset environment variable for resource detection to be an error. (#1170)
+- Rename `go.opentelemetry.io/otel/api/metric.ConfigureInstrument` to `NewInstrumentConfig` and
+  `go.opentelemetry.io/otel/api/metric.ConfigureMeter` to `NewMeterConfig`.
+- ValueObserver instruments use LastValue aggregator by default. (#1165)
+- OTLP Metric exporter supports LastValue aggregation. (#1165)
+- Move the `go.opentelemetry.io/otel/api/unit` package to `go.opentelemetry.io/otel/unit`. (#1185)
+- Rename `Provider` to `MeterProvider` in the `go.opentelemetry.io/otel/api/metric` package. (#1190)
+- Rename `NoopProvider` to `NoopMeterProvider` in the `go.opentelemetry.io/otel/api/metric` package. (#1190)
+- Rename `NewProvider` to `NewMeterProvider` in the `go.opentelemetry.io/otel/api/metric/metrictest` package. (#1190)
+- Rename `Provider` to `MeterProvider` in the `go.opentelemetry.io/otel/api/metric/registry` package. (#1190)
+- Rename `NewProvider` to `NewMeterProvider` in the `go.opentelemetry.io/otel/api/metri/registryc` package. (#1190)
+- Rename `Provider` to `TracerProvider` in the `go.opentelemetry.io/otel/api/trace` package. (#1190)
+- Rename `NoopProvider` to `NoopTracerProvider` in the `go.opentelemetry.io/otel/api/trace` package. (#1190)
+- Rename `Provider` to `TracerProvider` in the `go.opentelemetry.io/otel/api/trace/tracetest` package. (#1190)
+- Rename `NewProvider` to `NewTracerProvider` in the `go.opentelemetry.io/otel/api/trace/tracetest` package. (#1190)
+- Rename `WrapperProvider` to `WrapperTracerProvider` in the `go.opentelemetry.io/otel/bridge/opentracing` package. (#1190)
+- Rename `NewWrapperProvider` to `NewWrapperTracerProvider` in the `go.opentelemetry.io/otel/bridge/opentracing` package. (#1190)
+- Rename `Provider` method of the pull controller to `MeterProvider` in the `go.opentelemetry.io/otel/sdk/metric/controller/pull` package. (#1190)
+- Rename `Provider` method of the push controller to `MeterProvider` in the `go.opentelemetry.io/otel/sdk/metric/controller/push` package. (#1190)
+- Rename `ProviderOptions` to `TracerProviderConfig` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190)
+- Rename `ProviderOption` to `TracerProviderOption` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190)
+- Rename `Provider` to `TracerProvider` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190)
+- Rename `NewProvider` to `NewTracerProvider` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190)
+- Renamed `SamplingDecision` values to comply with OpenTelemetry specification change. (#1192)
+- Renamed Zipkin attribute names from `ot.status_code & ot.status_description` to `otel.status_code & otel.status_description`. (#1201)
+- The default SDK now invokes registered `SpanProcessor`s in the order they were registered with the `TracerProvider`. (#1195)
+- Add test of spans being processed by the `SpanProcessor`s in the order they were registered. (#1203)
+
+### Removed
+
+- Remove the B3 propagator from `go.opentelemetry.io/otel/propagators`. It is now located in the
+   `go.opentelemetry.io/contrib/propagators/` module. (#1191)
+- Remove the semantic convention for HTTP status text, `HTTPStatusTextKey` from package `go.opentelemetry.io/otel/semconv`. (#1194)
+
+### Fixed
+
+- Zipkin example no longer mentions `ParentSampler`, corrected to `ParentBased`. (#1171)
+- Fix missing shutdown processor in otel-collector example. (#1186)
+- Fix missing shutdown processor in basic and namedtracer examples. (#1197)
+
+## [0.11.0] - 2020-08-24
+
+### Added
+
+- Support for exporting array-valued attributes via OTLP. (#992)
+- `Noop` and `InMemory` `SpanBatcher` implementations to help with testing integrations. (#994)
+- Support for filtering metric label sets. (#1047)
+- A dimensionality-reducing metric Processor. (#1057)
+- Integration tests for more OTel Collector Attribute types. (#1062)
+- A new `WithSpanProcessor` `ProviderOption` is added to the `go.opentelemetry.io/otel/sdk/trace` package to create a `Provider` and automatically register the `SpanProcessor`. (#1078)
+
+### Changed
+
+- Rename `sdk/metric/processor/test` to `sdk/metric/processor/processortest`. (#1049)
+- Rename `sdk/metric/controller/test` to `sdk/metric/controller/controllertest`. (#1049)
+- Rename `api/testharness` to `api/apitest`. (#1049)
+- Rename `api/trace/testtrace` to `api/trace/tracetest`. (#1049)
+- Change Metric Processor to merge multiple observations. (#1024)
+- The `go.opentelemetry.io/otel/bridge/opentracing` bridge package has been made into its own module.
+   This removes the package dependencies of this bridge from the rest of the OpenTelemetry based project. (#1038)
+- Renamed `go.opentelemetry.io/otel/api/standard` package to `go.opentelemetry.io/otel/semconv` to avoid the ambiguous and generic name `standard` and better describe the package as containing OpenTelemetry semantic conventions. (#1016)
+- The environment variable used for resource detection has been changed from `OTEL_RESOURCE_LABELS` to `OTEL_RESOURCE_ATTRIBUTES` (#1042)
+- Replace `WithSyncer` with `WithBatcher` in examples. (#1044)
+- Replace the `google.golang.org/grpc/codes` dependency in the API with an equivalent `go.opentelemetry.io/otel/codes` package. (#1046)
+- Merge the `go.opentelemetry.io/otel/api/label` and `go.opentelemetry.io/otel/api/kv` into the new `go.opentelemetry.io/otel/label` package. (#1060)
+- Unify Callback Function Naming.
+   Rename `*Callback` with `*Func`. (#1061)
+- CI builds validate against last two versions of Go, dropping 1.13 and adding 1.15. (#1064)
+- The `go.opentelemetry.io/otel/sdk/export/trace` interfaces `SpanSyncer` and `SpanBatcher` have been replaced with a specification compliant `Exporter` interface.
+   This interface still supports the export of `SpanData`, but only as a slice.
+   Implementation are also required now to return any error from `ExportSpans` if one occurs as well as implement a `Shutdown` method for exporter clean-up. (#1078)
+- The `go.opentelemetry.io/otel/sdk/trace` `NewBatchSpanProcessor` function no longer returns an error.
+   If a `nil` exporter is passed as an argument to this function, instead of it returning an error, it now returns a `BatchSpanProcessor` that handles the export of `SpanData` by not taking any action. (#1078)
+- The `go.opentelemetry.io/otel/sdk/trace` `NewProvider` function to create a `Provider` no longer returns an error, instead only a `*Provider`.
+   This change is related to `NewBatchSpanProcessor` not returning an error which was the only error this function would return. (#1078)
+
+### Removed
+
+- Duplicate, unused API sampler interface. (#999)
+   Use the [`Sampler` interface](https://github.com/open-telemetry/opentelemetry-go/blob/v0.11.0/sdk/trace/sampling.go) provided by the SDK instead.
+- The `grpctrace` instrumentation was moved to the `go.opentelemetry.io/contrib` repository and out of this repository.
+   This move includes moving the `grpc` example to the `go.opentelemetry.io/contrib` as well. (#1027)
+- The `WithSpan` method of the `Tracer` interface.
+   The functionality this method provided was limited compared to what a user can provide themselves.
+   It was removed with the understanding that if there is sufficient user need it can be added back based on actual user usage. (#1043)
+- The `RegisterSpanProcessor` and `UnregisterSpanProcessor` functions.
+   These were holdovers from an approach prior to the TracerProvider design. They were not used anymore. (#1077)
+- The `oterror` package. (#1026)
+- The `othttp` and `httptrace` instrumentations were moved to `go.opentelemetry.io/contrib`. (#1032)
+
+### Fixed
+
+- The `semconv.HTTPServerMetricAttributesFromHTTPRequest()` function no longer generates the high-cardinality `http.request.content.length` label. (#1031)
+- Correct instrumentation version tag in Jaeger exporter. (#1037)
+- The SDK span will now set an error event if the `End` method is called during a panic (i.e. it was deferred). (#1043)
+- Move internally generated protobuf code from the `go.opentelemetry.io/otel` to the OTLP exporter to reduce dependency overhead. (#1050)
+- The `otel-collector` example referenced outdated collector processors. (#1006)
+
+## [0.10.0] - 2020-07-29
+
+This release migrates the default OpenTelemetry SDK into its own Go module, decoupling the SDK from the API and reducing dependencies for instrumentation packages.
+
+### Added
+
+- The Zipkin exporter now has `NewExportPipeline` and `InstallNewPipeline` constructor functions to match the common pattern.
+    These function build a new exporter with default SDK options and register the exporter with the `global` package respectively. (#944)
+- Add propagator option for gRPC instrumentation. (#986)
+- The `testtrace` package now tracks the `trace.SpanKind` for each span. (#987)
+
+### Changed
+
+- Replace the `RegisterGlobal` `Option` in the Jaeger exporter with an `InstallNewPipeline` constructor function.
+   This matches the other exporter constructor patterns and will register a new exporter after building it with default configuration. (#944)
+- The trace (`go.opentelemetry.io/otel/exporters/trace/stdout`) and metric (`go.opentelemetry.io/otel/exporters/metric/stdout`) `stdout` exporters are now merged into a single exporter at `go.opentelemetry.io/otel/exporters/stdout`.
+   This new exporter was made into its own Go module to follow the pattern of all exporters and decouple it from the `go.opentelemetry.io/otel` module. (#956, #963)
+- Move the `go.opentelemetry.io/otel/exporters/test` test package to `go.opentelemetry.io/otel/sdk/export/metric/metrictest`. (#962)
+- The `go.opentelemetry.io/otel/api/kv/value` package was merged into the parent `go.opentelemetry.io/otel/api/kv` package. (#968)
+  - `value.Bool` was replaced with `kv.BoolValue`.
+  - `value.Int64` was replaced with `kv.Int64Value`.
+  - `value.Uint64` was replaced with `kv.Uint64Value`.
+  - `value.Float64` was replaced with `kv.Float64Value`.
+  - `value.Int32` was replaced with `kv.Int32Value`.
+  - `value.Uint32` was replaced with `kv.Uint32Value`.
+  - `value.Float32` was replaced with `kv.Float32Value`.
+  - `value.String` was replaced with `kv.StringValue`.
+  - `value.Int` was replaced with `kv.IntValue`.
+  - `value.Uint` was replaced with `kv.UintValue`.
+  - `value.Array` was replaced with `kv.ArrayValue`.
+- Rename `Infer` to `Any` in the `go.opentelemetry.io/otel/api/kv` package. (#972)
+- Change `othttp` to use the `httpsnoop` package to wrap the `ResponseWriter` so that optional interfaces (`http.Hijacker`, `http.Flusher`, etc.) that are implemented by the original `ResponseWriter`are also implemented by the wrapped `ResponseWriter`. (#979)
+- Rename `go.opentelemetry.io/otel/sdk/metric/aggregator/test` package to `go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest`. (#980)
+- Make the SDK into its own Go module called `go.opentelemetry.io/otel/sdk`. (#985)
+- Changed the default trace `Sampler` from `AlwaysOn` to `ParentOrElse(AlwaysOn)`. (#989)
+
+### Removed
+
+- The `IndexedAttribute` function from the `go.opentelemetry.io/otel/api/label` package was removed in favor of `IndexedLabel` which it was synonymous with. (#970)
+
+### Fixed
+
+- Bump github.com/golangci/golangci-lint from 1.28.3 to 1.29.0 in /tools. (#953)
+- Bump github.com/google/go-cmp from 0.5.0 to 0.5.1. (#957)
+- Use `global.Handle` for span export errors in the OTLP exporter. (#946)
+- Correct Go language formatting in the README documentation. (#961)
+- Remove default SDK dependencies from the `go.opentelemetry.io/otel/api` package. (#977)
+- Remove default SDK dependencies from the `go.opentelemetry.io/otel/instrumentation` package. (#983)
+- Move documented examples for `go.opentelemetry.io/otel/instrumentation/grpctrace` interceptors into Go example tests. (#984)
+
+## [0.9.0] - 2020-07-20
+
+### Added
+
+- A new Resource Detector interface is included to allow resources to be automatically detected and included. (#939)
+- A Detector to automatically detect resources from an environment variable. (#939)
+- Github action to generate protobuf Go bindings locally in `internal/opentelemetry-proto-gen`. (#938)
+- OTLP .proto files from `open-telemetry/opentelemetry-proto` imported as a git submodule under `internal/opentelemetry-proto`.
+   References to `github.com/open-telemetry/opentelemetry-proto` changed to `go.opentelemetry.io/otel/internal/opentelemetry-proto-gen`. (#942)
+
+### Changed
+
+- Non-nil value `struct`s for key-value pairs will be marshalled using JSON rather than `Sprintf`. (#948)
+
+### Removed
+
+- Removed dependency on `github.com/open-telemetry/opentelemetry-collector`. (#943)
+
+## [0.8.0] - 2020-07-09
+
+### Added
+
+- The `B3Encoding` type to represent the B3 encoding(s) the B3 propagator can inject.
+   A value for HTTP supported encodings (Multiple Header: `MultipleHeader`, Single Header: `SingleHeader`) are included. (#882)
+- The `FlagsDeferred` trace flag to indicate if the trace sampling decision has been deferred. (#882)
+- The `FlagsDebug` trace flag to indicate if the trace is a debug trace. (#882)
+- Add `peer.service` semantic attribute. (#898)
+- Add database-specific semantic attributes. (#899)
+- Add semantic convention for `faas.coldstart` and `container.id`. (#909)
+- Add http content size semantic conventions. (#905)
+- Include `http.request_content_length` in HTTP request basic attributes. (#905)
+- Add semantic conventions for operating system process resource attribute keys. (#919)
+- The Jaeger exporter now has a `WithBatchMaxCount` option to specify the maximum number of spans sent in a batch. (#931)
+
+### Changed
+
+- Update `CONTRIBUTING.md` to ask for updates to `CHANGELOG.md` with each pull request. (#879)
+- Use lowercase header names for B3 Multiple Headers. (#881)
+- The B3 propagator `SingleHeader` field has been replaced with `InjectEncoding`.
+   This new field can be set to combinations of the `B3Encoding` bitmasks and will inject trace information in these encodings.
+   If no encoding is set, the propagator will default to `MultipleHeader` encoding. (#882)
+- The B3 propagator now extracts from either HTTP encoding of B3 (Single Header or Multiple Header) based on what is contained in the header.
+   Preference is given to Single Header encoding with Multiple Header being the fallback if Single Header is not found or is invalid.
+   This behavior change is made to dynamically support all correctly encoded traces received instead of having to guess the expected encoding prior to receiving. (#882)
+- Extend semantic conventions for RPC. (#900)
+- To match constant naming conventions in the `api/standard` package, the `FaaS*` key names are appended with a suffix of `Key`. (#920)
+  - `"api/standard".FaaSName` -> `FaaSNameKey`
+  - `"api/standard".FaaSID` -> `FaaSIDKey`
+  - `"api/standard".FaaSVersion` -> `FaaSVersionKey`
+  - `"api/standard".FaaSInstance` -> `FaaSInstanceKey`
+
+### Removed
+
+- The `FlagsUnused` trace flag is removed.
+   The purpose of this flag was to act as the inverse of `FlagsSampled`, the inverse of `FlagsSampled` is used instead. (#882)
+- The B3 header constants (`B3SingleHeader`, `B3DebugFlagHeader`, `B3TraceIDHeader`, `B3SpanIDHeader`, `B3SampledHeader`, `B3ParentSpanIDHeader`) are removed.
+   If B3 header keys are needed [the authoritative OpenZipkin package constants](https://pkg.go.dev/github.com/openzipkin/[email protected]/propagation/b3?tab=doc#pkg-constants) should be used instead. (#882)
+
+### Fixed
+
+- The B3 Single Header name is now correctly `b3` instead of the previous `X-B3`. (#881)
+- The B3 propagator now correctly supports sampling only values (`b3: 0`, `b3: 1`, or `b3: d`) for a Single B3 Header. (#882)
+- The B3 propagator now propagates the debug flag.
+   This removes the behavior of changing the debug flag into a set sampling bit.
+   Instead, this now follow the B3 specification and omits the `X-B3-Sampling` header. (#882)
+- The B3 propagator now tracks "unset" sampling state (meaning "defer the decision") and does not set the `X-B3-Sampling` header when injecting. (#882)
+- Bump github.com/itchyny/gojq from 0.10.3 to 0.10.4 in /tools. (#883)
+- Bump github.com/opentracing/opentracing-go from v1.1.1-0.20190913142402-a7454ce5950e to v1.2.0. (#885)
+- The tracing time conversion for OTLP spans is now correctly set to `UnixNano`. (#896)
+- Ensure span status is not set to `Unknown` when no HTTP status code is provided as it is assumed to be `200 OK`. (#908)
+- Ensure `httptrace.clientTracer` closes `http.headers` span. (#912)
+- Prometheus exporter will not apply stale updates or forget inactive metrics. (#903)
+- Add test for api.standard `HTTPClientAttributesFromHTTPRequest`. (#905)
+- Bump github.com/golangci/golangci-lint from 1.27.0 to 1.28.1 in /tools. (#901, #913)
+- Update otel-colector example to use the v0.5.0 collector. (#915)
+- The `grpctrace` instrumentation uses a span name conforming to the OpenTelemetry semantic conventions (does not contain a leading slash (`/`)). (#922)
+- The `grpctrace` instrumentation includes an `rpc.method` attribute now set to the gRPC method name. (#900, #922)
+- The `grpctrace` instrumentation `rpc.service` attribute now contains the package name if one exists.
+   This is in accordance with OpenTelemetry semantic conventions. (#922)
+- Correlation Context extractor will no longer insert an empty map into the returned context when no valid values are extracted. (#923)
+- Bump google.golang.org/api from 0.28.0 to 0.29.0 in /exporters/trace/jaeger. (#925)
+- Bump github.com/itchyny/gojq from 0.10.4 to 0.11.0 in /tools. (#926)
+- Bump github.com/golangci/golangci-lint from 1.28.1 to 1.28.2 in /tools. (#930)
+
+## [0.7.0] - 2020-06-26
+
+This release implements the v0.5.0 version of the OpenTelemetry specification.
+
+### Added
+
+- The othttp instrumentation now includes default metrics. (#861)
+- This CHANGELOG file to track all changes in the project going forward.
+- Support for array type attributes. (#798)
+- Apply transitive dependabot go.mod dependency updates as part of a new automatic Github workflow. (#844)
+- Timestamps are now passed to exporters for each export. (#835)
+- Add new `Accumulation` type to metric SDK to transport telemetry from `Accumulator`s to `Processor`s.
+   This replaces the prior `Record` `struct` use for this purpose. (#835)
+- New dependabot integration to automate package upgrades. (#814)
+- `Meter` and `Tracer` implementations accept instrumentation version version as an optional argument.
+   This instrumentation version is passed on to exporters. (#811) (#805) (#802)
+- The OTLP exporter includes the instrumentation version in telemetry it exports. (#811)
+- Environment variables for Jaeger exporter are supported. (#796)
+- New `aggregation.Kind` in the export metric API. (#808)
+- New example that uses OTLP and the collector. (#790)
+- Handle errors in the span `SetName` during span initialization. (#791)
+- Default service config to enable retries for retry-able failed requests in the OTLP exporter and an option to override this default. (#777)
+- New `go.opentelemetry.io/otel/api/oterror` package to uniformly support error handling and definitions for the project. (#778)
+- New `global` default implementation of the `go.opentelemetry.io/otel/api/oterror.Handler` interface to be used to handle errors prior to an user defined `Handler`.
+   There is also functionality for the user to register their `Handler` as well as a convenience function `Handle` to handle an error with this global `Handler`(#778)
+- Options to specify propagators for httptrace and grpctrace instrumentation. (#784)
+- The required `application/json` header for the Zipkin exporter is included in all exports. (#774)
+- Integrate HTTP semantics helpers from the contrib repository into the `api/standard` package. #769
+
+### Changed
+
+- Rename `Integrator` to `Processor` in the metric SDK. (#863)
+- Rename `AggregationSelector` to `AggregatorSelector`. (#859)
+- Rename `SynchronizedCopy` to `SynchronizedMove`. (#858)
+- Rename `simple` integrator to `basic` integrator. (#857)
+- Merge otlp collector examples. (#841)
+- Change the metric SDK to support cumulative, delta, and pass-through exporters directly.
+   With these changes, cumulative and delta specific exporters are able to request the correct kind of aggregation from the SDK. (#840)
+- The `Aggregator.Checkpoint` API is renamed to `SynchronizedCopy` and adds an argument, a different `Aggregator` into which the copy is stored. (#812)
+- The `export.Aggregator` contract is that `Update()` and `SynchronizedCopy()` are synchronized with each other.
+   All the aggregation interfaces (`Sum`, `LastValue`, ...) are not meant to be synchronized, as the caller is expected to synchronize aggregators at a higher level after the `Accumulator`.
+   Some of the `Aggregators` used unnecessary locking and that has been cleaned up. (#812)
+- Use of `metric.Number` was replaced by `int64` now that we use `sync.Mutex` in the `MinMaxSumCount` and `Histogram` `Aggregators`. (#812)
+- Replace `AlwaysParentSample` with `ParentSample(fallback)` to match the OpenTelemetry v0.5.0 specification. (#810)
+- Rename `sdk/export/metric/aggregator` to `sdk/export/metric/aggregation`. #808
+- Send configured headers with every request in the OTLP exporter, instead of just on connection creation. (#806)
+- Update error handling for any one off error handlers, replacing, instead, with the `global.Handle` function. (#791)
+- Rename `plugin` directory to `instrumentation` to match the OpenTelemetry specification. (#779)
+- Makes the argument order to Histogram and DDSketch `New()` consistent. (#781)
+
+### Removed
+
+- `Uint64NumberKind` and related functions from the API. (#864)
+- Context arguments from `Aggregator.Checkpoint` and `Integrator.Process` as they were unused. (#803)
+- `SpanID` is no longer included in parameters for sampling decision to match the OpenTelemetry specification. (#775)
+
+### Fixed
+
+- Upgrade OTLP exporter to opentelemetry-proto matching the opentelemetry-collector v0.4.0 release. (#866)
+- Allow changes to `go.sum` and `go.mod` when running dependabot tidy-up. (#871)
+- Bump github.com/stretchr/testify from 1.4.0 to 1.6.1. (#824)
+- Bump github.com/prometheus/client_golang from 1.7.0 to 1.7.1 in /exporters/metric/prometheus. (#867)
+- Bump google.golang.org/grpc from 1.29.1 to 1.30.0 in /exporters/trace/jaeger. (#853)
+- Bump google.golang.org/grpc from 1.29.1 to 1.30.0 in /exporters/trace/zipkin. (#854)
+- Bumps github.com/golang/protobuf from 1.3.2 to 1.4.2 (#848)
+- Bump github.com/stretchr/testify from 1.4.0 to 1.6.1 in /exporters/otlp (#817)
+- Bump github.com/golangci/golangci-lint from 1.25.1 to 1.27.0 in /tools (#828)
+- Bump github.com/prometheus/client_golang from 1.5.0 to 1.7.0 in /exporters/metric/prometheus (#838)
+- Bump github.com/stretchr/testify from 1.4.0 to 1.6.1 in /exporters/trace/jaeger (#829)
+- Bump github.com/benbjohnson/clock from 1.0.0 to 1.0.3 (#815)
+- Bump github.com/stretchr/testify from 1.4.0 to 1.6.1 in /exporters/trace/zipkin (#823)
+- Bump github.com/itchyny/gojq from 0.10.1 to 0.10.3 in /tools (#830)
+- Bump github.com/stretchr/testify from 1.4.0 to 1.6.1 in /exporters/metric/prometheus (#822)
+- Bump google.golang.org/grpc from 1.27.1 to 1.29.1 in /exporters/trace/zipkin (#820)
+- Bump google.golang.org/grpc from 1.27.1 to 1.29.1 in /exporters/trace/jaeger (#831)
+- Bump github.com/google/go-cmp from 0.4.0 to 0.5.0 (#836)
+- Bump github.com/google/go-cmp from 0.4.0 to 0.5.0 in /exporters/trace/jaeger (#837)
+- Bump github.com/google/go-cmp from 0.4.0 to 0.5.0 in /exporters/otlp (#839)
+- Bump google.golang.org/api from 0.20.0 to 0.28.0 in /exporters/trace/jaeger (#843)
+- Set span status from HTTP status code in the othttp instrumentation. (#832)
+- Fixed typo in push controller comment. (#834)
+- The `Aggregator` testing has been updated and cleaned. (#812)
+- `metric.Number(0)` expressions are replaced by `0` where possible. (#812)
+- Fixed `global` `handler_test.go` test failure. #804
+- Fixed `BatchSpanProcessor.Shutdown` to wait until all spans are processed. (#766)
+- Fixed OTLP example's accidental early close of exporter. (#807)
+- Ensure zipkin exporter reads and closes response body. (#788)
+- Update instrumentation to use `api/standard` keys instead of custom keys. (#782)
+- Clean up tools and RELEASING documentation. (#762)
+
+## [0.6.0] - 2020-05-21
+
+### Added
+
+- Support for `Resource`s in the prometheus exporter. (#757)
+- New pull controller. (#751)
+- New `UpDownSumObserver` instrument. (#750)
+- OpenTelemetry collector demo. (#711)
+- New `SumObserver` instrument. (#747)
+- New `UpDownCounter` instrument. (#745)
+- New timeout `Option` and configuration function `WithTimeout` to the push controller. (#742)
+- New `api/standards` package to implement semantic conventions and standard key-value generation. (#731)
+
+### Changed
+
+- Rename `Register*` functions in the metric API to `New*` for all `Observer` instruments. (#761)
+- Use `[]float64` for histogram boundaries, not `[]metric.Number`. (#758)
+- Change OTLP example to use exporter as a trace `Syncer` instead of as an unneeded `Batcher`. (#756)
+- Replace `WithResourceAttributes()` with `WithResource()` in the trace SDK. (#754)
+- The prometheus exporter now uses the new pull controller. (#751)
+- Rename `ScheduleDelayMillis` to `BatchTimeout` in the trace `BatchSpanProcessor`.(#752)
+- Support use of synchronous instruments in asynchronous callbacks (#725)
+- Move `Resource` from the `Export` method parameter into the metric export `Record`. (#739)
+- Rename `Observer` instrument to `ValueObserver`. (#734)
+- The push controller now has a method (`Provider()`) to return a `metric.Provider` instead of the old `Meter` method that acted as a `metric.Provider`. (#738)
+- Replace `Measure` instrument by `ValueRecorder` instrument. (#732)
+- Rename correlation context header from `"Correlation-Context"` to `"otcorrelations"` to match the OpenTelemetry specification. (#727)
+
+### Fixed
+
+- Ensure gRPC `ClientStream` override methods do not panic in grpctrace package. (#755)
+- Disable parts of `BatchSpanProcessor` test until a fix is found. (#743)
+- Fix `string` case in `kv` `Infer` function. (#746)
+- Fix panic in grpctrace client interceptors. (#740)
+- Refactor the `api/metrics` push controller and add `CheckpointSet` synchronization. (#737)
+- Rewrite span batch process queue batching logic. (#719)
+- Remove the push controller named Meter map. (#738)
+- Fix Histogram aggregator initial state (fix #735). (#736)
+- Ensure golang alpine image is running `golang-1.14` for examples. (#733)
+- Added test for grpctrace `UnaryInterceptorClient`. (#695)
+- Rearrange `api/metric` code layout. (#724)
+
+## [0.5.0] - 2020-05-13
+
+### Added
+
+- Batch `Observer` callback support. (#717)
+- Alias `api` types to root package of project. (#696)
+- Create basic `othttp.Transport` for simple client instrumentation. (#678)
+- `SetAttribute(string, interface{})` to the trace API. (#674)
+- Jaeger exporter option that allows user to specify custom http client. (#671)
+- `Stringer` and `Infer` methods to `key`s. (#662)
+
+### Changed
+
+- Rename `NewKey` in the `kv` package to just `Key`. (#721)
+- Move `core` and `key` to `kv` package. (#720)
+- Make the metric API `Meter` a `struct` so the abstract `MeterImpl` can be passed and simplify implementation. (#709)
+- Rename SDK `Batcher` to `Integrator` to match draft OpenTelemetry SDK specification. (#710)
+- Rename SDK `Ungrouped` integrator to `simple.Integrator` to match draft OpenTelemetry SDK specification. (#710)
+- Rename SDK `SDK` `struct` to `Accumulator` to match draft OpenTelemetry SDK specification. (#710)
+- Move `Number` from `core` to `api/metric` package. (#706)
+- Move `SpanContext` from `core` to `trace` package. (#692)
+- Change traceparent header from `Traceparent` to `traceparent` to implement the W3C specification. (#681)
+
+### Fixed
+
+- Update tooling to run generators in all submodules. (#705)
+- gRPC interceptor regexp to match methods without a service name. (#683)
+- Use a `const` for padding 64-bit B3 trace IDs. (#701)
+- Update `mockZipkin` listen address from `:0` to `127.0.0.1:0`. (#700)
+- Left-pad 64-bit B3 trace IDs with zero. (#698)
+- Propagate at least the first W3C tracestate header. (#694)
+- Remove internal `StateLocker` implementation. (#688)
+- Increase instance size CI system uses. (#690)
+- Add a `key` benchmark and use reflection in `key.Infer()`. (#679)
+- Fix internal `global` test by using `global.Meter` with `RecordBatch()`. (#680)
+- Reimplement histogram using mutex instead of `StateLocker`. (#669)
+- Switch `MinMaxSumCount` to a mutex lock implementation instead of `StateLocker`. (#667)
+- Update documentation to not include any references to `WithKeys`. (#672)
+- Correct misspelling. (#668)
+- Fix clobbering of the span context if extraction fails. (#656)
+- Bump `golangci-lint` and work around the corrupting bug. (#666) (#670)
+
+## [0.4.3] - 2020-04-24
+
+### Added
+
+- `Dockerfile` and `docker-compose.yml` to run example code. (#635)
+- New `grpctrace` package that provides gRPC client and server interceptors for both unary and stream connections. (#621)
+- New `api/label` package, providing common label set implementation. (#651)
+- Support for JSON marshaling of `Resources`. (#654)
+- `TraceID` and `SpanID` implementations for `Stringer` interface. (#642)
+- `RemoteAddrKey` in the othttp plugin to include the HTTP client address in top-level spans. (#627)
+- `WithSpanFormatter` option to the othttp plugin. (#617)
+- Updated README to include section for compatible libraries and include reference to the contrib repository. (#612)
+- The prometheus exporter now supports exporting histograms. (#601)
+- A `String` method to the `Resource` to return a hashable identifier for a now unique resource. (#613)
+- An `Iter` method to the `Resource` to return an array `AttributeIterator`. (#613)
+- An `Equal` method to the `Resource` test the equivalence of resources. (#613)
+- An iterable structure (`AttributeIterator`) for `Resource` attributes.
+
+### Changed
+
+- zipkin export's `NewExporter` now requires a `serviceName` argument to ensure this needed values is provided. (#644)
+- Pass `Resources` through the metrics export pipeline. (#659)
+
+### Removed
+
+- `WithKeys` option from the metric API. (#639)
+
+### Fixed
+
+- Use the `label.Set.Equivalent` value instead of an encoding in the batcher. (#658)
+- Correct typo `trace.Exporter` to `trace.SpanSyncer` in comments. (#653)
+- Use type names for return values in jaeger exporter. (#648)
+- Increase the visibility of the `api/key` package by updating comments and fixing usages locally. (#650)
+- `Checkpoint` only after `Update`; Keep records in the `sync.Map` longer. (#647)
+- Do not cache `reflect.ValueOf()` in metric Labels. (#649)
+- Batch metrics exported from the OTLP exporter based on `Resource` and labels. (#626)
+- Add error wrapping to the prometheus exporter. (#631)
+- Update the OTLP exporter batching of traces to use a unique `string` representation of an associated `Resource` as the batching key. (#623)
+- Update OTLP `SpanData` transform to only include the `ParentSpanID` if one exists. (#614)
+- Update `Resource` internal representation to uniquely and reliably identify resources. (#613)
+- Check return value from `CheckpointSet.ForEach` in prometheus exporter. (#622)
+- Ensure spans created by httptrace client tracer reflect operation structure. (#618)
+- Create a new recorder rather than reuse when multiple observations in same epoch for asynchronous instruments. #610
+- The default port the OTLP exporter uses to connect to the OpenTelemetry collector is updated to match the one the collector listens on by default. (#611)
+
+## [0.4.2] - 2020-03-31
+
+### Fixed
+
+- Fix `pre_release.sh` to update version in `sdk/opentelemetry.go`. (#607)
+- Fix time conversion from internal to OTLP in OTLP exporter. (#606)
+
+## [0.4.1] - 2020-03-31
+
+### Fixed
+
+- Update `tag.sh` to create signed tags. (#604)
+
+## [0.4.0] - 2020-03-30
+
+### Added
+
+- New API package `api/metric/registry` that exposes a `MeterImpl` wrapper for use by SDKs to generate unique instruments. (#580)
+- Script to verify examples after a new release. (#579)
+
+### Removed
+
+- The dogstatsd exporter due to lack of support.
+   This additionally removes support for statsd. (#591)
+- `LabelSet` from the metric API.
+   This is replaced by a `[]core.KeyValue` slice. (#595)
+- `Labels` from the metric API's `Meter` interface. (#595)
+
+### Changed
+
+- The metric `export.Labels` became an interface which the SDK implements and the `export` package provides a simple, immutable implementation of this interface intended for testing purposes. (#574)
+- Renamed `internal/metric.Meter` to `MeterImpl`. (#580)
+- Renamed `api/global/internal.obsImpl` to `asyncImpl`. (#580)
+
+### Fixed
+
+- Corrected missing return in mock span. (#582)
+- Update License header for all source files to match CNCF guidelines and include a test to ensure it is present. (#586) (#596)
+- Update to v0.3.0 of the OTLP in the OTLP exporter. (#588)
+- Update pre-release script to be compatible between GNU and BSD based systems. (#592)
+- Add a `RecordBatch` benchmark. (#594)
+- Moved span transforms of the OTLP exporter to the internal package. (#593)
+- Build both go-1.13 and go-1.14 in circleci to test for all supported versions of Go. (#569)
+- Removed unneeded allocation on empty labels in OLTP exporter. (#597)
+- Update `BatchedSpanProcessor` to process the queue until no data but respect max batch size. (#599)
+- Update project documentation godoc.org links to pkg.go.dev. (#602)
+
+## [0.3.0] - 2020-03-21
+
+This is a first official beta release, which provides almost fully complete metrics, tracing, and context propagation functionality.
+There is still a possibility of breaking changes.
+
+### Added
+
+- Add `Observer` metric instrument. (#474)
+- Add global `Propagators` functionality to enable deferred initialization for propagators registered before the first Meter SDK is installed. (#494)
+- Simplified export setup pipeline for the jaeger exporter to match other exporters. (#459)
+- The zipkin trace exporter. (#495)
+- The OTLP exporter to export metric and trace telemetry to the OpenTelemetry collector. (#497) (#544) (#545)
+- Add `StatusMessage` field to the trace `Span`. (#524)
+- Context propagation in OpenTracing bridge in terms of OpenTelemetry context propagation. (#525)
+- The `Resource` type was added to the SDK. (#528)
+- The global API now supports a `Tracer` and `Meter` function as shortcuts to getting a global `*Provider` and calling these methods directly. (#538)
+- The metric API now defines a generic `MeterImpl` interface to support general purpose `Meter` construction.
+   Additionally, `SyncImpl` and `AsyncImpl` are added to support general purpose instrument construction. (#560)
+- A metric `Kind` is added to represent the `MeasureKind`, `ObserverKind`, and `CounterKind`. (#560)
+- Scripts to better automate the release process. (#576)
+
+### Changed
+
+- Default to to use `AlwaysSampler` instead of `ProbabilitySampler` to match OpenTelemetry specification. (#506)
+- Renamed `AlwaysSampleSampler` to `AlwaysOnSampler` in the trace API. (#511)
+- Renamed `NeverSampleSampler` to `AlwaysOffSampler` in the trace API. (#511)
+- The `Status` field of the `Span` was changed to `StatusCode` to disambiguate with the added `StatusMessage`. (#524)
+- Updated the trace `Sampler` interface conform to the OpenTelemetry specification. (#531)
+- Rename metric API `Options` to `Config`. (#541)
+- Rename metric `Counter` aggregator to be `Sum`. (#541)
+- Unify metric options into `Option` from instrument specific options. (#541)
+- The trace API's `TraceProvider` now support `Resource`s. (#545)
+- Correct error in zipkin module name. (#548)
+- The jaeger trace exporter now supports `Resource`s. (#551)
+- Metric SDK now supports `Resource`s.
+   The `WithResource` option was added to configure a `Resource` on creation and the `Resource` method was added to the metric `Descriptor` to return the associated `Resource`. (#552)
+- Replace `ErrNoLastValue` and `ErrEmptyDataSet` by `ErrNoData` in the metric SDK. (#557)
+- The stdout trace exporter now supports `Resource`s. (#558)
+- The metric `Descriptor` is now included at the API instead of the SDK. (#560)
+- Replace `Ordered` with an iterator in `export.Labels`. (#567)
+
+### Removed
+
+- The vendor specific Stackdriver. It is now hosted on 3rd party vendor infrastructure. (#452)
+- The `Unregister` method for metric observers as it is not in the OpenTelemetry specification. (#560)
+- `GetDescriptor` from the metric SDK. (#575)
+- The `Gauge` instrument from the metric API. (#537)
+
+### Fixed
+
+- Make histogram aggregator checkpoint consistent. (#438)
+- Update README with import instructions and how to build and test. (#505)
+- The default label encoding was updated to be unique. (#508)
+- Use `NewRoot` in the othttp plugin for public endpoints. (#513)
+- Fix data race in `BatchedSpanProcessor`. (#518)
+- Skip test-386 for Mac OS 10.15.x (Catalina and upwards). #521
+- Use a variable-size array to represent ordered labels in maps. (#523)
+- Update the OTLP protobuf and update changed import path. (#532)
+- Use `StateLocker` implementation in `MinMaxSumCount`. (#546)
+- Eliminate goroutine leak in histogram stress test. (#547)
+- Update OTLP exporter with latest protobuf. (#550)
+- Add filters to the othttp plugin. (#556)
+- Provide an implementation of the `Header*` filters that do not depend on Go 1.14. (#565)
+- Encode labels once during checkpoint.
+   The checkpoint function is executed in a single thread so we can do the encoding lazily before passing the encoded version of labels to the exporter.
+   This is a cheap and quick way to avoid encoding the labels on every collection interval. (#572)
+- Run coverage over all packages in `COVERAGE_MOD_DIR`. (#573)
+
+## [0.2.3] - 2020-03-04
+
+### Added
+
+- `RecordError` method on `Span`s in the trace API to Simplify adding error events to spans. (#473)
+- Configurable push frequency for exporters setup pipeline. (#504)
+
+### Changed
+
+- Rename the `exporter` directory to `exporters`.
+   The `go.opentelemetry.io/otel/exporter/trace/jaeger` package was mistakenly released with a `v1.0.0` tag instead of `v0.1.0`.
+   This resulted in all subsequent releases not becoming the default latest.
+   A consequence of this was that all `go get`s pulled in the incompatible `v0.1.0` release of that package when pulling in more recent packages from other otel packages.
+   Renaming the `exporter` directory to `exporters` fixes this issue by renaming the package and therefore clearing any existing dependency tags.
+   Consequentially, this action also renames *all* exporter packages. (#502)
+
+### Removed
+
+- The `CorrelationContextHeader` constant in the `correlation` package is no longer exported. (#503)
+
+## [0.2.2] - 2020-02-27
+
+### Added
+
+- `HTTPSupplier` interface in the propagation API to specify methods to retrieve and store a single value for a key to be associated with a carrier. (#467)
+- `HTTPExtractor` interface in the propagation API to extract information from an `HTTPSupplier` into a context. (#467)
+- `HTTPInjector` interface in the propagation API to inject information into an `HTTPSupplier.` (#467)
+- `Config` and configuring `Option` to the propagator API. (#467)
+- `Propagators` interface in the propagation API to contain the set of injectors and extractors for all supported carrier formats. (#467)
+- `HTTPPropagator` interface in the propagation API to inject and extract from an `HTTPSupplier.` (#467)
+- `WithInjectors` and `WithExtractors` functions to the propagator API to configure injectors and extractors to use. (#467)
+- `ExtractHTTP` and `InjectHTTP` functions to apply configured HTTP extractors and injectors to a passed context. (#467)
+- Histogram aggregator. (#433)
+- `DefaultPropagator` function and have it return `trace.TraceContext` as the default context propagator. (#456)
+- `AlwaysParentSample` sampler to the trace API. (#455)
+- `WithNewRoot` option function to the trace API to specify the created span should be considered a root span. (#451)
+
+### Changed
+
+- Renamed `WithMap` to `ContextWithMap` in the correlation package. (#481)
+- Renamed `FromContext` to `MapFromContext` in the correlation package. (#481)
+- Move correlation context propagation to correlation package. (#479)
+- Do not default to putting remote span context into links. (#480)
+- `Tracer.WithSpan` updated to accept `StartOptions`. (#472)
+- Renamed `MetricKind` to `Kind` to not stutter in the type usage. (#432)
+- Renamed the `export` package to `metric` to match directory structure. (#432)
+- Rename the `api/distributedcontext` package to `api/correlation`. (#444)
+- Rename the `api/propagators` package to `api/propagation`. (#444)
+- Move the propagators from the `propagators` package into the `trace` API package. (#444)
+- Update `Float64Gauge`, `Int64Gauge`, `Float64Counter`, `Int64Counter`, `Float64Measure`, and `Int64Measure` metric methods to use value receivers instead of pointers. (#462)
+- Moved all dependencies of tools package to a tools directory. (#466)
+
+### Removed
+
+- Binary propagators. (#467)
+- NOOP propagator. (#467)
+
+### Fixed
+
+- Upgraded `github.com/golangci/golangci-lint` from `v1.21.0` to `v1.23.6` in `tools/`. (#492)
+- Fix a possible nil-dereference crash (#478)
+- Correct comments for `InstallNewPipeline` in the stdout exporter. (#483)
+- Correct comments for `InstallNewPipeline` in the dogstatsd exporter. (#484)
+- Correct comments for `InstallNewPipeline` in the prometheus exporter. (#482)
+- Initialize `onError` based on `Config` in prometheus exporter. (#486)
+- Correct module name in prometheus exporter README. (#475)
+- Removed tracer name prefix from span names. (#430)
+- Fix `aggregator_test.go` import package comment. (#431)
+- Improved detail in stdout exporter. (#436)
+- Fix a dependency issue (generate target should depend on stringer, not lint target) in Makefile. (#442)
+- Reorders the Makefile targets within `precommit` target so we generate files and build the code before doing linting, so we can get much nicer errors about syntax errors from the compiler. (#442)
+- Reword function documentation in gRPC plugin. (#446)
+- Send the `span.kind` tag to Jaeger from the jaeger exporter. (#441)
+- Fix `metadataSupplier` in the jaeger exporter to overwrite the header if existing instead of appending to it. (#441)
+- Upgraded to Go 1.13 in CI. (#465)
+- Correct opentelemetry.io URL in trace SDK documentation. (#464)
+- Refactored reference counting logic in SDK determination of stale records. (#468)
+- Add call to `runtime.Gosched` in instrument `acquireHandle` logic to not block the collector. (#469)
+
+## [0.2.1.1] - 2020-01-13
+
+### Fixed
+
+- Use stateful batcher on Prometheus exporter fixing regression introduced in #395. (#428)
+
+## [0.2.1] - 2020-01-08
+
+### Added
+
+- Global meter forwarding implementation.
+   This enables deferred initialization for metric instruments registered before the first Meter SDK is installed. (#392)
+- Global trace forwarding implementation.
+   This enables deferred initialization for tracers registered before the first Trace SDK is installed. (#406)
+- Standardize export pipeline creation in all exporters. (#395)
+- A testing, organization, and comments for 64-bit field alignment. (#418)
+- Script to tag all modules in the project. (#414)
+
+### Changed
+
+- Renamed `propagation` package to `propagators`. (#362)
+- Renamed `B3Propagator` propagator to `B3`. (#362)
+- Renamed `TextFormatPropagator` propagator to `TextFormat`. (#362)
+- Renamed `BinaryPropagator` propagator to `Binary`. (#362)
+- Renamed `BinaryFormatPropagator` propagator to `BinaryFormat`. (#362)
+- Renamed `NoopTextFormatPropagator` propagator to `NoopTextFormat`. (#362)
+- Renamed `TraceContextPropagator` propagator to `TraceContext`. (#362)
+- Renamed `SpanOption` to `StartOption` in the trace API. (#369)
+- Renamed `StartOptions` to `StartConfig` in the trace API. (#369)
+- Renamed `EndOptions` to `EndConfig` in the trace API. (#369)
+- `Number` now has a pointer receiver for its methods. (#375)
+- Renamed `CurrentSpan` to `SpanFromContext` in the trace API. (#379)
+- Renamed `SetCurrentSpan` to `ContextWithSpan` in the trace API. (#379)
+- Renamed `Message` in Event to `Name` in the trace API. (#389)
+- Prometheus exporter no longer aggregates metrics, instead it only exports them. (#385)
+- Renamed `HandleImpl` to `BoundInstrumentImpl` in the metric API. (#400)
+- Renamed `Float64CounterHandle` to `Float64CounterBoundInstrument` in the metric API. (#400)
+- Renamed `Int64CounterHandle` to `Int64CounterBoundInstrument` in the metric API. (#400)
+- Renamed `Float64GaugeHandle` to `Float64GaugeBoundInstrument` in the metric API. (#400)
+- Renamed `Int64GaugeHandle` to `Int64GaugeBoundInstrument` in the metric API. (#400)
+- Renamed `Float64MeasureHandle` to `Float64MeasureBoundInstrument` in the metric API. (#400)
+- Renamed `Int64MeasureHandle` to `Int64MeasureBoundInstrument` in the metric API. (#400)
+- Renamed `Release` method for bound instruments in the metric API to `Unbind`. (#400)
+- Renamed `AcquireHandle` method for bound instruments in the metric API to `Bind`. (#400)
+- Renamed the `File` option in the stdout exporter to `Writer`. (#404)
+- Renamed all `Options` to `Config` for all metric exports where this wasn't already the case.
+
+### Fixed
+
+- Aggregator import path corrected. (#421)
+- Correct links in README. (#368)
+- The README was updated to match latest code changes in its examples. (#374)
+- Don't capitalize error statements. (#375)
+- Fix ignored errors. (#375)
+- Fix ambiguous variable naming. (#375)
+- Removed unnecessary type casting. (#375)
+- Use named parameters. (#375)
+- Updated release schedule. (#378)
+- Correct http-stackdriver example module name. (#394)
+- Removed the `http.request` span in `httptrace` package. (#397)
+- Add comments in the metrics SDK (#399)
+- Initialize checkpoint when creating ddsketch aggregator to prevent panic when merging into a empty one. (#402) (#403)
+- Add documentation of compatible exporters in the README. (#405)
+- Typo fix. (#408)
+- Simplify span check logic in SDK tracer implementation. (#419)
+
+## [0.2.0] - 2019-12-03
+
+### Added
+
+- Unary gRPC tracing example. (#351)
+- Prometheus exporter. (#334)
+- Dogstatsd metrics exporter. (#326)
+
+### Changed
+
+- Rename `MaxSumCount` aggregation to `MinMaxSumCount` and add the `Min` interface for this aggregation. (#352)
+- Rename `GetMeter` to `Meter`. (#357)
+- Rename `HTTPTraceContextPropagator` to `TraceContextPropagator`. (#355)
+- Rename `HTTPB3Propagator` to `B3Propagator`. (#355)
+- Rename `HTTPTraceContextPropagator` to `TraceContextPropagator`. (#355)
+- Move `/global` package to `/api/global`. (#356)
+- Rename `GetTracer` to `Tracer`. (#347)
+
+### Removed
+
+- `SetAttribute` from the `Span` interface in the trace API. (#361)
+- `AddLink` from the `Span` interface in the trace API. (#349)
+- `Link` from the `Span` interface in the trace API. (#349)
+
+### Fixed
+
+- Exclude example directories from coverage report. (#365)
+- Lint make target now implements automatic fixes with `golangci-lint` before a second run to report the remaining issues. (#360)
+- Drop `GO111MODULE` environment variable in Makefile as Go 1.13 is the project specified minimum version and this is environment variable is not needed for that version of Go. (#359)
+- Run the race checker for all test. (#354)
+- Redundant commands in the Makefile are removed. (#354)
+- Split the `generate` and `lint` targets of the Makefile. (#354)
+- Renames `circle-ci` target to more generic `ci` in Makefile. (#354)
+- Add example Prometheus binary to gitignore. (#358)
+- Support negative numbers with the `MaxSumCount`. (#335)
+- Resolve race conditions in `push_test.go` identified in #339. (#340)
+- Use `/usr/bin/env bash` as a shebang in scripts rather than `/bin/bash`. (#336)
+- Trace benchmark now tests both `AlwaysSample` and `NeverSample`.
+   Previously it was testing `AlwaysSample` twice. (#325)
+- Trace benchmark now uses a `[]byte` for `TraceID` to fix failing test. (#325)
+- Added a trace benchmark to test variadic functions in `setAttribute` vs `setAttributes` (#325)
+- The `defaultkeys` batcher was only using the encoded label set as its map key while building a checkpoint.
+   This allowed distinct label sets through, but any metrics sharing a label set could be overwritten or merged incorrectly.
+   This was corrected. (#333)
+
+## [0.1.2] - 2019-11-18
+
+### Fixed
+
+- Optimized the `simplelru` map for attributes to reduce the number of allocations. (#328)
+- Removed unnecessary unslicing of parameters that are already a slice. (#324)
+
+## [0.1.1] - 2019-11-18
+
+This release contains a Metrics SDK with stdout exporter and supports basic aggregations such as counter, gauges, array, maxsumcount, and ddsketch.
+
+### Added
+
+- Metrics stdout export pipeline. (#265)
+- Array aggregation for raw measure metrics. (#282)
+- The core.Value now have a `MarshalJSON` method. (#281)
+
+### Removed
+
+- `WithService`, `WithResources`, and `WithComponent` methods of tracers. (#314)
+- Prefix slash in `Tracer.Start()` for the Jaeger example. (#292)
+
+### Changed
+
+- Allocation in LabelSet construction to reduce GC overhead. (#318)
+- `trace.WithAttributes` to append values instead of replacing (#315)
+- Use a formula for tolerance in sampling tests. (#298)
+- Move export types into trace and metric-specific sub-directories. (#289)
+- `SpanKind` back to being based on an `int` type. (#288)
+
+### Fixed
+
+- URL to OpenTelemetry website in README. (#323)
+- Name of othttp default tracer. (#321)
+- `ExportSpans` for the stackdriver exporter now handles `nil` context. (#294)
+- CI modules cache to correctly restore/save from/to the cache. (#316)
+- Fix metric SDK race condition between `LoadOrStore` and the assignment `rec.recorder = i.meter.exporter.AggregatorFor(rec)`. (#293)
+- README now reflects the new code structure introduced with these changes. (#291)
+- Make the basic example work. (#279)
+
+## [0.1.0] - 2019-11-04
+
+This is the first release of open-telemetry go library.
+It contains api and sdk for trace and meter.
+
+### Added
+
+- Initial OpenTelemetry trace and metric API prototypes.
+- Initial OpenTelemetry trace, metric, and export SDK packages.
+- A wireframe bridge to support compatibility with OpenTracing.
+- Example code for a basic, http-stackdriver, http, jaeger, and named tracer setup.
+- Exporters for Jaeger, Stackdriver, and stdout.
+- Propagators for binary, B3, and trace-context protocols.
+- Project information and guidelines in the form of a README and CONTRIBUTING.
+- Tools to build the project and a Makefile to automate the process.
+- Apache-2.0 license.
+- CircleCI build CI manifest files.
+- CODEOWNERS file to track owners of this project.
+
+[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.19.0...HEAD
+[1.19.0/0.42.0/0.0.7]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0
+[1.19.0-rc.1/0.42.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0-rc.1
+[1.18.0/0.41.0/0.0.6]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.18.0
+[1.17.0/0.40.0/0.0.5]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.17.0
+[1.16.0/0.39.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.16.0
+[1.16.0-rc.1/0.39.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.16.0-rc.1
+[1.15.1/0.38.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.1
+[1.15.0/0.38.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0
+[1.15.0-rc.2/0.38.0-rc.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0-rc.2
+[1.15.0-rc.1/0.38.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0-rc.1
+[1.14.0/0.37.0/0.0.4]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.14.0
+[1.13.0/0.36.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.13.0
+[1.12.0/0.35.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.12.0
+[1.11.2/0.34.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.11.2
+[1.11.1/0.33.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.11.1
+[1.11.0/0.32.3]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.11.0
+[0.32.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/sdk/metric/v0.32.2
+[0.32.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/sdk/metric/v0.32.1
+[0.32.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/sdk/metric/v0.32.0
+[1.10.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.10.0
+[1.9.0/0.0.3]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.9.0
+[1.8.0/0.31.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.8.0
+[1.7.0/0.30.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.7.0
+[0.29.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/metric/v0.29.0
+[1.6.3]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.6.3
+[1.6.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.6.2
+[1.6.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.6.1
+[1.6.0/0.28.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.6.0
+[1.5.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.5.0
+[1.4.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.4.1
+[1.4.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.4.0
+[1.3.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.3.0
+[1.2.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.2.0
+[1.1.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.1.0
+[1.0.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.0.1
+[Metrics 0.24.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/metric/v0.24.0
+[1.0.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.0.0
+[1.0.0-RC3]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.0.0-RC3
+[1.0.0-RC2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.0.0-RC2
+[Experimental Metrics v0.22.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/metric/v0.22.0
+[1.0.0-RC1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.0.0-RC1
+[0.20.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.20.0
+[0.19.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.19.0
+[0.18.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.18.0
+[0.17.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.17.0
+[0.16.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.16.0
+[0.15.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.15.0
+[0.14.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.14.0
+[0.13.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.13.0
+[0.12.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.12.0
+[0.11.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.11.0
+[0.10.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.10.0
+[0.9.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.9.0
+[0.8.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.8.0
+[0.7.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.7.0
+[0.6.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.6.0
+[0.5.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.5.0
+[0.4.3]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.4.3
+[0.4.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.4.2
+[0.4.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.4.1
+[0.4.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.4.0
+[0.3.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.3.0
+[0.2.3]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.2.3
+[0.2.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.2.2
+[0.2.1.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.2.1.1
+[0.2.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.2.1
+[0.2.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.2.0
+[0.1.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.2
+[0.1.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.1
+[0.1.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.0
+
+[Go 1.20]: https://go.dev/doc/go1.20
+[Go 1.19]: https://go.dev/doc/go1.19
+[Go 1.18]: https://go.dev/doc/go1.18
+[Go 1.19]: https://go.dev/doc/go1.19
+
+[metric API]:https://pkg.go.dev/go.opentelemetry.io/otel/metric
+[metric SDK]:https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric

+ 17 - 0
pkg/go.opentelemetry.io/otel/CODEOWNERS

@@ -0,0 +1,17 @@
+#####################################################
+#
+# List of approvers for this repository
+#
+#####################################################
+#
+# Learn about membership in OpenTelemetry community:
+#  https://github.com/open-telemetry/community/blob/main/community-membership.md
+#
+#
+# Learn about CODEOWNERS file format:
+#  https://help.github.com/en/articles/about-code-owners
+#
+
+* @MrAlias @Aneurysm9 @evantorrie @XSAM @dashpole @MadVikingGod @pellared @hanyuancheung @dmathieu
+
+CODEOWNERS @MrAlias @MadVikingGod @pellared

+ 620 - 0
pkg/go.opentelemetry.io/otel/CONTRIBUTING.md

@@ -0,0 +1,620 @@
+# Contributing to opentelemetry-go
+
+The Go special interest group (SIG) meets regularly. See the
+OpenTelemetry
+[community](https://github.com/open-telemetry/community#golang-sdk)
+repo for information on this and other language SIGs.
+
+See the [public meeting
+notes](https://docs.google.com/document/d/1E5e7Ld0NuU1iVvf-42tOBpu2VBBLYnh73GJuITGJTTU/edit)
+for a summary description of past meetings. To request edit access,
+join the meeting or get in touch on
+[Slack](https://cloud-native.slack.com/archives/C01NPAXACKT).
+
+## Development
+
+You can view and edit the source code by cloning this repository:
+
+```sh
+git clone https://github.com/open-telemetry/opentelemetry-go.git
+```
+
+Run `make test` to run the tests instead of `go test`.
+
+There are some generated files checked into the repo. To make sure
+that the generated files are up-to-date, run `make` (or `make
+precommit` - the `precommit` target is the default).
+
+The `precommit` target also fixes the formatting of the code and
+checks the status of the go module files.
+
+Additionally, there is a `codespell` target that checks for common
+typos in the code. It is not run by default, but you can run it
+manually with `make codespell`. It will set up a virtual environment
+in `venv` and install `codespell` there.
+
+If after running `make precommit` the output of `git status` contains
+`nothing to commit, working tree clean` then it means that everything
+is up-to-date and properly formatted.
+
+## Pull Requests
+
+### How to Send Pull Requests
+
+Everyone is welcome to contribute code to `opentelemetry-go` via
+GitHub pull requests (PRs).
+
+To create a new PR, fork the project in GitHub and clone the upstream
+repo:
+
+```sh
+go get -d go.opentelemetry.io/otel
+```
+
+(This may print some warning about "build constraints exclude all Go
+files", just ignore it.)
+
+This will put the project in `${GOPATH}/src/go.opentelemetry.io/otel`. You
+can alternatively use `git` directly with:
+
+```sh
+git clone https://github.com/open-telemetry/opentelemetry-go
+```
+
+(Note that `git clone` is *not* using the `go.opentelemetry.io/otel` name -
+that name is a kind of a redirector to GitHub that `go get` can
+understand, but `git` does not.)
+
+This would put the project in the `opentelemetry-go` directory in
+current working directory.
+
+Enter the newly created directory and add your fork as a new remote:
+
+```sh
+git remote add <YOUR_FORK> [email protected]:<YOUR_GITHUB_USERNAME>/opentelemetry-go
+```
+
+Check out a new branch, make modifications, run linters and tests, update
+`CHANGELOG.md`, and push the branch to your fork:
+
+```sh
+git checkout -b <YOUR_BRANCH_NAME>
+# edit files
+# update changelog
+make precommit
+git add -p
+git commit
+git push <YOUR_FORK> <YOUR_BRANCH_NAME>
+```
+
+Open a pull request against the main `opentelemetry-go` repo. Be sure to add the pull
+request ID to the entry you added to `CHANGELOG.md`.
+
+### How to Receive Comments
+
+* If the PR is not ready for review, please put `[WIP]` in the title,
+  tag it as `work-in-progress`, or mark it as
+  [`draft`](https://github.blog/2019-02-14-introducing-draft-pull-requests/).
+* Make sure CLA is signed and CI is clear.
+
+### How to Get PRs Merged
+
+A PR is considered **ready to merge** when:
+
+* It has received two qualified approvals[^1].
+
+  This is not enforced through automation, but needs to be validated by the
+  maintainer merging.
+  * The qualified approvals need to be from [Approver]s/[Maintainer]s
+    affiliated with different companies. Two qualified approvals from
+    [Approver]s or [Maintainer]s affiliated with the same company counts as a
+    single qualified approval.
+  * PRs introducing changes that have already been discussed and consensus
+    reached only need one qualified approval. The discussion and resolution
+    needs to be linked to the PR.
+  * Trivial changes[^2] only need one qualified approval.
+
+* All feedback has been addressed.
+  * All PR comments and suggestions are resolved.
+  * All GitHub Pull Request reviews with a status of "Request changes" have
+    been addressed. Another review by the objecting reviewer with a different
+    status can be submitted to clear the original review, or the review can be
+    dismissed by a [Maintainer] when the issues from the original review have
+    been addressed.
+  * Any comments or reviews that cannot be resolved between the PR author and
+    reviewers can be submitted to the community [Approver]s and [Maintainer]s
+    during the weekly SIG meeting. If consensus is reached among the
+    [Approver]s and [Maintainer]s during the SIG meeting the objections to the
+    PR may be dismissed or resolved or the PR closed by a [Maintainer].
+  * Any substantive changes to the PR require existing Approval reviews be
+    cleared unless the approver explicitly states that their approval persists
+    across changes. This includes changes resulting from other feedback.
+    [Approver]s and [Maintainer]s can help in clearing reviews and they should
+    be consulted if there are any questions.
+
+* The PR branch is up to date with the base branch it is merging into.
+  * To ensure this does not block the PR, it should be configured to allow
+    maintainers to update it.
+
+* It has been open for review for at least one working day. This gives people
+  reasonable time to review.
+  * Trivial changes[^2] do not have to wait for one day and may be merged with
+    a single [Maintainer]'s approval.
+
+* All required GitHub workflows have succeeded.
+* Urgent fix can take exception as long as it has been actively communicated
+  among [Maintainer]s.
+
+Any [Maintainer] can merge the PR once the above criteria have been met.
+
+[^1]: A qualified approval is a GitHub Pull Request review with "Approve"
+  status from an OpenTelemetry Go [Approver] or [Maintainer].
+[^2]: Trivial changes include: typo corrections, cosmetic non-substantive
+  changes, documentation corrections or updates, dependency updates, etc.
+
+## Design Choices
+
+As with other OpenTelemetry clients, opentelemetry-go follows the
+[OpenTelemetry Specification](https://opentelemetry.io/docs/specs/otel).
+
+It's especially valuable to read through the [library
+guidelines](https://opentelemetry.io/docs/specs/otel/library-guidelines).
+
+### Focus on Capabilities, Not Structure Compliance
+
+OpenTelemetry is an evolving specification, one where the desires and
+use cases are clear, but the method to satisfy those uses cases are
+not.
+
+As such, Contributions should provide functionality and behavior that
+conforms to the specification, but the interface and structure is
+flexible.
+
+It is preferable to have contributions follow the idioms of the
+language rather than conform to specific API names or argument
+patterns in the spec.
+
+For a deeper discussion, see
+[this](https://github.com/open-telemetry/opentelemetry-specification/issues/165).
+
+## Documentation
+
+Each (non-internal, non-test) package must be documented using
+[Go Doc Comments](https://go.dev/doc/comment),
+preferably in a `doc.go` file.
+
+Prefer using [Examples](https://pkg.go.dev/testing#hdr-Examples)
+instead of putting code snippets in Go doc comments.
+In some cases, you can even create [Testable Examples](https://go.dev/blog/examples).
+
+You can install and run a "local Go Doc site" in the following way:
+
+  ```sh
+  go install golang.org/x/pkgsite/cmd/pkgsite@latest
+  pkgsite
+  ```
+
+[`go.opentelemetry.io/otel/metric`](https://pkg.go.dev/go.opentelemetry.io/otel/metric)
+is an example of a very well-documented package.
+
+## Style Guide
+
+One of the primary goals of this project is that it is actually used by
+developers. With this goal in mind the project strives to build
+user-friendly and idiomatic Go code adhering to the Go community's best
+practices.
+
+For a non-comprehensive but foundational overview of these best practices
+the [Effective Go](https://golang.org/doc/effective_go.html) documentation
+is an excellent starting place.
+
+As a convenience for developers building this project the `make precommit`
+will format, lint, validate, and in some cases fix the changes you plan to
+submit. This check will need to pass for your changes to be able to be
+merged.
+
+In addition to idiomatic Go, the project has adopted certain standards for
+implementations of common patterns. These standards should be followed as a
+default, and if they are not followed documentation needs to be included as
+to the reasons why.
+
+### Configuration
+
+When creating an instantiation function for a complex `type T struct`, it is
+useful to allow variable number of options to be applied. However, the strong
+type system of Go restricts the function design options. There are a few ways
+to solve this problem, but we have landed on the following design.
+
+#### `config`
+
+Configuration should be held in a `struct` named `config`, or prefixed with
+specific type name this Configuration applies to if there are multiple
+`config` in the package. This type must contain configuration options.
+
+```go
+// config contains configuration options for a thing.
+type config struct {
+	// options ...
+}
+```
+
+In general the `config` type will not need to be used externally to the
+package and should be unexported. If, however, it is expected that the user
+will likely want to build custom options for the configuration, the `config`
+should be exported. Please, include in the documentation for the `config`
+how the user can extend the configuration.
+
+It is important that internal `config` are not shared across package boundaries.
+Meaning a `config` from one package should not be directly used by another. The
+one exception is the API packages.  The configs from the base API, eg.
+`go.opentelemetry.io/otel/trace.TracerConfig` and
+`go.opentelemetry.io/otel/metric.InstrumentConfig`, are intended to be consumed
+by the SDK therefore it is expected that these are exported.
+
+When a config is exported we want to maintain forward and backward
+compatibility, to achieve this no fields should be exported but should
+instead be accessed by methods.
+
+Optionally, it is common to include a `newConfig` function (with the same
+naming scheme). This function wraps any defaults setting and looping over
+all options to create a configured `config`.
+
+```go
+// newConfig returns an appropriately configured config.
+func newConfig(options ...Option) config {
+	// Set default values for config.
+	config := config{/* […] */}
+	for _, option := range options {
+		config = option.apply(config)
+	}
+	// Perform any validation here.
+	return config
+}
+```
+
+If validation of the `config` options is also performed this can return an
+error as well that is expected to be handled by the instantiation function
+or propagated to the user.
+
+Given the design goal of not having the user need to work with the `config`,
+the `newConfig` function should also be unexported.
+
+#### `Option`
+
+To set the value of the options a `config` contains, a corresponding
+`Option` interface type should be used.
+
+```go
+type Option interface {
+	apply(config) config
+}
+```
+
+Having `apply` unexported makes sure that it will not be used externally.
+Moreover, the interface becomes sealed so the user cannot easily implement
+the interface on its own.
+
+The `apply` method should return a modified version of the passed config.
+This approach, instead of passing a pointer, is used to prevent the config from being allocated to the heap.
+
+The name of the interface should be prefixed in the same way the
+corresponding `config` is (if at all).
+
+#### Options
+
+All user configurable options for a `config` must have a related unexported
+implementation of the `Option` interface and an exported configuration
+function that wraps this implementation.
+
+The wrapping function name should be prefixed with `With*` (or in the
+special case of a boolean options `Without*`) and should have the following
+function signature.
+
+```go
+func With*(…) Option { … }
+```
+
+##### `bool` Options
+
+```go
+type defaultFalseOption bool
+
+func (o defaultFalseOption) apply(c config) config {
+	c.Bool = bool(o)
+    return c
+}
+
+// WithOption sets a T to have an option included.
+func WithOption() Option {
+	return defaultFalseOption(true)
+}
+```
+
+```go
+type defaultTrueOption bool
+
+func (o defaultTrueOption) apply(c config) config {
+	c.Bool = bool(o)
+    return c
+}
+
+// WithoutOption sets a T to have Bool option excluded.
+func WithoutOption() Option {
+	return defaultTrueOption(false)
+}
+```
+
+##### Declared Type Options
+
+```go
+type myTypeOption struct {
+	MyType MyType
+}
+
+func (o myTypeOption) apply(c config) config {
+	c.MyType = o.MyType
+    return c
+}
+
+// WithMyType sets T to have include MyType.
+func WithMyType(t MyType) Option {
+	return myTypeOption{t}
+}
+```
+
+##### Functional Options
+
+```go
+type optionFunc func(config) config
+
+func (fn optionFunc) apply(c config) config {
+	return fn(c)
+}
+
+// WithMyType sets t as MyType.
+func WithMyType(t MyType) Option {
+	return optionFunc(func(c config) config {
+		c.MyType = t
+        return c
+	})
+}
+```
+
+#### Instantiation
+
+Using this configuration pattern to configure instantiation with a `NewT`
+function.
+
+```go
+func NewT(options ...Option) T {…}
+```
+
+Any required parameters can be declared before the variadic `options`.
+
+#### Dealing with Overlap
+
+Sometimes there are multiple complex `struct` that share common
+configuration and also have distinct configuration. To avoid repeated
+portions of `config`s, a common `config` can be used with the union of
+options being handled with the `Option` interface.
+
+For example.
+
+```go
+// config holds options for all animals.
+type config struct {
+	Weight      float64
+	Color       string
+	MaxAltitude float64
+}
+
+// DogOption apply Dog specific options.
+type DogOption interface {
+	applyDog(config) config
+}
+
+// BirdOption apply Bird specific options.
+type BirdOption interface {
+	applyBird(config) config
+}
+
+// Option apply options for all animals.
+type Option interface {
+	BirdOption
+	DogOption
+}
+
+type weightOption float64
+
+func (o weightOption) applyDog(c config) config {
+	c.Weight = float64(o)
+	return c
+}
+
+func (o weightOption) applyBird(c config) config {
+	c.Weight = float64(o)
+	return c
+}
+
+func WithWeight(w float64) Option { return weightOption(w) }
+
+type furColorOption string
+
+func (o furColorOption) applyDog(c config) config {
+	c.Color = string(o)
+	return c
+}
+
+func WithFurColor(c string) DogOption { return furColorOption(c) }
+
+type maxAltitudeOption float64
+
+func (o maxAltitudeOption) applyBird(c config) config {
+	c.MaxAltitude = float64(o)
+	return c
+}
+
+func WithMaxAltitude(a float64) BirdOption { return maxAltitudeOption(a) }
+
+func NewDog(name string, o ...DogOption) Dog    {…}
+func NewBird(name string, o ...BirdOption) Bird {…}
+```
+
+### Interfaces
+
+To allow other developers to better comprehend the code, it is important
+to ensure it is sufficiently documented. One simple measure that contributes
+to this aim is self-documenting by naming method parameters. Therefore,
+where appropriate, methods of every exported interface type should have
+their parameters appropriately named.
+
+#### Interface Stability
+
+All exported stable interfaces that include the following warning in their
+documentation are allowed to be extended with additional methods.
+
+> Warning: methods may be added to this interface in minor releases.
+
+These interfaces are defined by the OpenTelemetry specification and will be
+updated as the specification evolves.
+
+Otherwise, stable interfaces MUST NOT be modified.
+
+#### How to Change Specification Interfaces
+
+When an API change must be made, we will update the SDK with the new method one
+release before the API change. This will allow the SDK one version before the
+API change to work seamlessly with the new API.
+
+If an incompatible version of the SDK is used with the new API the application
+will fail to compile.
+
+#### How Not to Change Specification Interfaces
+
+We have explored using a v2 of the API to change interfaces and found that there
+was no way to introduce a v2 and have it work seamlessly with the v1 of the API.
+Problems happened with libraries that upgraded to v2 when an application did not,
+and would not produce any telemetry.
+
+More detail of the approaches considered and their limitations can be found in
+the [Use a V2 API to evolve interfaces](https://github.com/open-telemetry/opentelemetry-go/issues/3920)
+issue.
+
+#### How to Change Other Interfaces
+
+If new functionality is needed for an interface that cannot be changed it MUST
+be added by including an additional interface. That added interface can be a
+simple interface for the specific functionality that you want to add or it can
+be a super-set of the original interface. For example, if you wanted to a
+`Close` method to the `Exporter` interface:
+
+```go
+type Exporter interface {
+	Export()
+}
+```
+
+A new interface, `Closer`, can be added:
+
+```go
+type Closer interface {
+	Close()
+}
+```
+
+Code that is passed the `Exporter` interface can now check to see if the passed
+value also satisfies the new interface. E.g.
+
+```go
+func caller(e Exporter) {
+	/* ... */
+	if c, ok := e.(Closer); ok {
+		c.Close()
+	}
+	/* ... */
+}
+```
+
+Alternatively, a new type that is the super-set of an `Exporter` can be created.
+
+```go
+type ClosingExporter struct {
+	Exporter
+	Close()
+}
+```
+
+This new type can be used similar to the simple interface above in that a
+passed `Exporter` type can be asserted to satisfy the `ClosingExporter` type
+and the `Close` method called.
+
+This super-set approach can be useful if there is explicit behavior that needs
+to be coupled with the original type and passed as a unified type to a new
+function, but, because of this coupling, it also limits the applicability of
+the added functionality. If there exist other interfaces where this
+functionality should be added, each one will need their own super-set
+interfaces and will duplicate the pattern. For this reason, the simple targeted
+interface that defines the specific functionality should be preferred.
+
+### Testing
+
+The tests should never leak goroutines.
+
+Use the term `ConcurrentSafe` in the test name when it aims to verify the
+absence of race conditions.
+
+### Internal packages
+
+The use of internal packages should be scoped to a single module. A sub-module
+should never import from a parent internal package. This creates a coupling
+between the two modules where a user can upgrade the parent without the child
+and if the internal package API has changed it will fail to upgrade[^3].
+
+There are two known exceptions to this rule:
+
+- `go.opentelemetry.io/otel/internal/global`
+  - This package manages global state for all of opentelemetry-go. It needs to
+  be a single package in order to ensure the uniqueness of the global state.
+- `go.opentelemetry.io/otel/internal/baggage`
+  - This package provides values in a `context.Context` that need to be
+  recognized by `go.opentelemetry.io/otel/baggage` and
+  `go.opentelemetry.io/otel/bridge/opentracing` but remain private.
+
+If you have duplicate code in multiple modules, make that code into a Go
+template stored in `go.opentelemetry.io/otel/internal/shared` and use [gotmpl]
+to render the templates in the desired locations. See [#4404] for an example of
+this.
+
+[^3]: https://github.com/open-telemetry/opentelemetry-go/issues/3548
+
+## Approvers and Maintainers
+
+### Approvers
+
+- [Evan Torrie](https://github.com/evantorrie), Verizon Media
+- [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics
+- [David Ashpole](https://github.com/dashpole), Google
+- [Chester Cheung](https://github.com/hanyuancheung), Tencent
+- [Damien Mathieu](https://github.com/dmathieu), Elastic
+- [Anthony Mirabella](https://github.com/Aneurysm9), AWS
+
+### Maintainers
+
+- [Aaron Clawson](https://github.com/MadVikingGod), LightStep
+- [Robert Pająk](https://github.com/pellared), Splunk
+- [Tyler Yahn](https://github.com/MrAlias), Splunk
+
+### Emeritus
+
+- [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep
+- [Josh MacDonald](https://github.com/jmacd), LightStep
+
+### Become an Approver or a Maintainer
+
+See the [community membership document in OpenTelemetry community
+repo](https://github.com/open-telemetry/community/blob/main/community-membership.md).
+
+[Approver]: #approvers
+[Maintainer]: #maintainers
+[gotmpl]: https://pkg.go.dev/go.opentelemetry.io/build-tools/gotmpl
+[#4404]: https://github.com/open-telemetry/opentelemetry-go/pull/4404

+ 201 - 0
pkg/go.opentelemetry.io/otel/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 291 - 0
pkg/go.opentelemetry.io/otel/Makefile

@@ -0,0 +1,291 @@
+# Copyright The OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+TOOLS_MOD_DIR := ./internal/tools
+
+ALL_DOCS := $(shell find . -name '*.md' -type f | sort)
+ALL_GO_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort)
+OTEL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(ALL_GO_MOD_DIRS))
+ALL_COVERAGE_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | grep -E -v '^./example|^$(TOOLS_MOD_DIR)' | sort)
+
+GO = go
+TIMEOUT = 60
+
+.DEFAULT_GOAL := precommit
+
+.PHONY: precommit ci
+precommit: generate dependabot-generate license-check misspell go-mod-tidy golangci-lint-fix test-default
+ci: generate dependabot-check license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage
+
+# Tools
+
+TOOLS = $(CURDIR)/.tools
+
+$(TOOLS):
+	@mkdir -p $@
+$(TOOLS)/%: | $(TOOLS)
+	cd $(TOOLS_MOD_DIR) && \
+	$(GO) build -o $@ $(PACKAGE)
+
+MULTIMOD = $(TOOLS)/multimod
+$(TOOLS)/multimod: PACKAGE=go.opentelemetry.io/build-tools/multimod
+
+SEMCONVGEN = $(TOOLS)/semconvgen
+$(TOOLS)/semconvgen: PACKAGE=go.opentelemetry.io/build-tools/semconvgen
+
+CROSSLINK = $(TOOLS)/crosslink
+$(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/build-tools/crosslink
+
+SEMCONVKIT = $(TOOLS)/semconvkit
+$(TOOLS)/semconvkit: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/semconvkit
+
+DBOTCONF = $(TOOLS)/dbotconf
+$(TOOLS)/dbotconf: PACKAGE=go.opentelemetry.io/build-tools/dbotconf
+
+GOLANGCI_LINT = $(TOOLS)/golangci-lint
+$(TOOLS)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint
+
+MISSPELL = $(TOOLS)/misspell
+$(TOOLS)/misspell: PACKAGE=github.com/client9/misspell/cmd/misspell
+
+GOCOVMERGE = $(TOOLS)/gocovmerge
+$(TOOLS)/gocovmerge: PACKAGE=github.com/wadey/gocovmerge
+
+STRINGER = $(TOOLS)/stringer
+$(TOOLS)/stringer: PACKAGE=golang.org/x/tools/cmd/stringer
+
+PORTO = $(TOOLS)/porto
+$(TOOLS)/porto: PACKAGE=github.com/jcchavezs/porto/cmd/porto
+
+GOJQ = $(TOOLS)/gojq
+$(TOOLS)/gojq: PACKAGE=github.com/itchyny/gojq/cmd/gojq
+
+GOTMPL = $(TOOLS)/gotmpl
+$(GOTMPL): PACKAGE=go.opentelemetry.io/build-tools/gotmpl
+
+GORELEASE = $(TOOLS)/gorelease
+$(GORELEASE): PACKAGE=golang.org/x/exp/cmd/gorelease
+
+.PHONY: tools
+tools: $(CROSSLINK) $(DBOTCONF) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
+
+# Virtualized python tools via docker
+
+# The directory where the virtual environment is created.
+VENVDIR := venv
+
+# The directory where the python tools are installed.
+PYTOOLS := $(VENVDIR)/bin
+
+# The pip executable in the virtual environment.
+PIP := $(PYTOOLS)/pip
+
+# The directory in the docker image where the current directory is mounted.
+WORKDIR := /workdir
+
+# The python image to use for the virtual environment.
+PYTHONIMAGE := python:3.11.3-slim-bullseye
+
+# Run the python image with the current directory mounted.
+DOCKERPY := docker run --rm -v "$(CURDIR):$(WORKDIR)" -w $(WORKDIR) $(PYTHONIMAGE)
+
+# Create a virtual environment for Python tools.
+$(PYTOOLS):
+# The `--upgrade` flag is needed to ensure that the virtual environment is
+# created with the latest pip version.
+	@$(DOCKERPY) bash -c "python3 -m venv $(VENVDIR) && $(PIP) install --upgrade pip"
+
+# Install python packages into the virtual environment.
+$(PYTOOLS)/%: | $(PYTOOLS)
+	@$(DOCKERPY) $(PIP) install -r requirements.txt
+
+CODESPELL = $(PYTOOLS)/codespell
+$(CODESPELL): PACKAGE=codespell
+
+# Generate
+
+.PHONY: generate
+generate: go-generate vanity-import-fix
+
+.PHONY: go-generate
+go-generate: $(OTEL_GO_MOD_DIRS:%=go-generate/%)
+go-generate/%: DIR=$*
+go-generate/%: | $(STRINGER) $(GOTMPL)
+	@echo "$(GO) generate $(DIR)/..." \
+		&& cd $(DIR) \
+		&& PATH="$(TOOLS):$${PATH}" $(GO) generate ./...
+
+.PHONY: vanity-import-fix
+vanity-import-fix: | $(PORTO)
+	@$(PORTO) --include-internal -w .
+
+# Generate go.work file for local development.
+.PHONY: go-work
+go-work: | $(CROSSLINK)
+	$(CROSSLINK) work --root=$(shell pwd)
+
+# Build
+
+.PHONY: build
+
+build: $(OTEL_GO_MOD_DIRS:%=build/%) $(OTEL_GO_MOD_DIRS:%=build-tests/%)
+build/%: DIR=$*
+build/%:
+	@echo "$(GO) build $(DIR)/..." \
+		&& cd $(DIR) \
+		&& $(GO) build ./...
+
+build-tests/%: DIR=$*
+build-tests/%:
+	@echo "$(GO) build tests $(DIR)/..." \
+		&& cd $(DIR) \
+		&& $(GO) list ./... \
+		| grep -v third_party \
+		| xargs $(GO) test -vet=off -run xxxxxMatchNothingxxxxx >/dev/null
+
+# Tests
+
+TEST_TARGETS := test-default test-bench test-short test-verbose test-race
+.PHONY: $(TEST_TARGETS) test
+test-default test-race: ARGS=-race
+test-bench:   ARGS=-run=xxxxxMatchNothingxxxxx -test.benchtime=1ms -bench=.
+test-short:   ARGS=-short
+test-verbose: ARGS=-v -race
+$(TEST_TARGETS): test
+test: $(OTEL_GO_MOD_DIRS:%=test/%)
+test/%: DIR=$*
+test/%:
+	@echo "$(GO) test -timeout $(TIMEOUT)s $(ARGS) $(DIR)/..." \
+		&& cd $(DIR) \
+		&& $(GO) list ./... \
+		| grep -v third_party \
+		| xargs $(GO) test -timeout $(TIMEOUT)s $(ARGS)
+
+COVERAGE_MODE    = atomic
+COVERAGE_PROFILE = coverage.out
+.PHONY: test-coverage
+test-coverage: | $(GOCOVMERGE)
+	@set -e; \
+	printf "" > coverage.txt; \
+	for dir in $(ALL_COVERAGE_MOD_DIRS); do \
+	  echo "$(GO) test -coverpkg=go.opentelemetry.io/otel/... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" $${dir}/..."; \
+	  (cd "$${dir}" && \
+	    $(GO) list ./... \
+	    | grep -v third_party \
+	    | grep -v 'semconv/v.*' \
+	    | xargs $(GO) test -coverpkg=./... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" && \
+	  $(GO) tool cover -html=coverage.out -o coverage.html); \
+	done; \
+	$(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt
+
+.PHONY: golangci-lint golangci-lint-fix
+golangci-lint-fix: ARGS=--fix
+golangci-lint-fix: golangci-lint
+golangci-lint: $(OTEL_GO_MOD_DIRS:%=golangci-lint/%)
+golangci-lint/%: DIR=$*
+golangci-lint/%: | $(GOLANGCI_LINT)
+	@echo 'golangci-lint $(if $(ARGS),$(ARGS) ,)$(DIR)' \
+		&& cd $(DIR) \
+		&& $(GOLANGCI_LINT) run --allow-serial-runners $(ARGS)
+
+.PHONY: crosslink
+crosslink: | $(CROSSLINK)
+	@echo "Updating intra-repository dependencies in all go modules" \
+		&& $(CROSSLINK) --root=$(shell pwd) --prune
+
+.PHONY: go-mod-tidy
+go-mod-tidy: $(ALL_GO_MOD_DIRS:%=go-mod-tidy/%)
+go-mod-tidy/%: DIR=$*
+go-mod-tidy/%: | crosslink
+	@echo "$(GO) mod tidy in $(DIR)" \
+		&& cd $(DIR) \
+		&& $(GO) mod tidy -compat=1.20
+
+.PHONY: lint-modules
+lint-modules: go-mod-tidy
+
+.PHONY: lint
+lint: misspell lint-modules golangci-lint
+
+.PHONY: vanity-import-check
+vanity-import-check: | $(PORTO)
+	@$(PORTO) --include-internal -l . || ( echo "(run: make vanity-import-fix)"; exit 1 )
+
+.PHONY: misspell
+misspell: | $(MISSPELL)
+	@$(MISSPELL) -w $(ALL_DOCS)
+
+.PHONY: codespell
+codespell: | $(CODESPELL)
+	@$(DOCKERPY) $(CODESPELL)
+
+.PHONY: license-check
+license-check:
+	@licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './.git/*' ) ; do \
+	           awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \
+	   done); \
+	   if [ -n "$${licRes}" ]; then \
+	           echo "license header checking failed:"; echo "$${licRes}"; \
+	           exit 1; \
+	   fi
+
+DEPENDABOT_CONFIG = .github/dependabot.yml
+.PHONY: dependabot-check
+dependabot-check: | $(DBOTCONF)
+	@$(DBOTCONF) verify $(DEPENDABOT_CONFIG) || ( echo "(run: make dependabot-generate)"; exit 1 )
+
+.PHONY: dependabot-generate
+dependabot-generate: | $(DBOTCONF)
+	@$(DBOTCONF) generate > $(DEPENDABOT_CONFIG)
+
+.PHONY: check-clean-work-tree
+check-clean-work-tree:
+	@if ! git diff --quiet; then \
+	  echo; \
+	  echo 'Working tree is not clean, did you forget to run "make precommit"?'; \
+	  echo; \
+	  git status; \
+	  exit 1; \
+	fi
+
+SEMCONVPKG ?= "semconv/"
+.PHONY: semconv-generate
+semconv-generate: | $(SEMCONVGEN) $(SEMCONVKIT)
+	[ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry semantic-conventions tag"; exit 1 )
+	[ "$(OTEL_SEMCONV_REPO)" ] || ( echo "OTEL_SEMCONV_REPO unset: missing path to opentelemetry semantic-conventions repo"; exit 1 )
+	$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=span -p conventionType=trace -f trace.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
+	$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=attribute_group -p conventionType=trace -f attribute_group.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
+	$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=event -p conventionType=event -f event.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
+	$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=resource -p conventionType=resource -f resource.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
+	$(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)"
+
+.PHONY: gorelease
+gorelease: $(OTEL_GO_MOD_DIRS:%=gorelease/%)
+gorelease/%: DIR=$*
+gorelease/%:| $(GORELEASE)
+	@echo "gorelease in $(DIR):" \
+		&& cd $(DIR) \
+		&& $(GORELEASE) \
+		|| echo ""
+
+.PHONY: prerelease
+prerelease: | $(MULTIMOD)
+	@[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
+	$(MULTIMOD) verify && $(MULTIMOD) prerelease -m ${MODSET}
+
+COMMIT ?= "HEAD"
+.PHONY: add-tags
+add-tags: | $(MULTIMOD)
+	@[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
+	$(MULTIMOD) verify && $(MULTIMOD) tag -m ${MODSET} -c ${COMMIT}

+ 111 - 0
pkg/go.opentelemetry.io/otel/README.md

@@ -0,0 +1,111 @@
+# OpenTelemetry-Go
+
+[![CI](https://github.com/open-telemetry/opentelemetry-go/workflows/ci/badge.svg)](https://github.com/open-telemetry/opentelemetry-go/actions?query=workflow%3Aci+branch%3Amain)
+[![codecov.io](https://codecov.io/gh/open-telemetry/opentelemetry-go/coverage.svg?branch=main)](https://app.codecov.io/gh/open-telemetry/opentelemetry-go?branch=main)
+[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel)](https://pkg.go.dev/go.opentelemetry.io/otel)
+[![Go Report Card](https://goreportcard.com/badge/go.opentelemetry.io/otel)](https://goreportcard.com/report/go.opentelemetry.io/otel)
+[![Slack](https://img.shields.io/badge/slack-@cncf/otel--go-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C01NPAXACKT)
+
+OpenTelemetry-Go is the [Go](https://golang.org/) implementation of [OpenTelemetry](https://opentelemetry.io/).
+It provides a set of APIs to directly measure performance and behavior of your software and send this data to observability platforms.
+
+## Project Status
+
+| Signal  | Status     | Project               |
+|---------|------------|-----------------------|
+| Traces  | Stable     | N/A                   |
+| Metrics | Mixed [1]  | [Go: Metric SDK (GA)] |
+| Logs    | Frozen [2] | N/A                   |
+
+[Go: Metric SDK (GA)]: https://github.com/orgs/open-telemetry/projects/34
+
+- [1]: [Metrics API](https://pkg.go.dev/go.opentelemetry.io/otel/metric) is Stable. [Metrics SDK](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric) is Beta.
+- [2]: The Logs signal development is halted for this project while we stabilize the Metrics SDK.
+   No Logs Pull Requests are currently being accepted.
+
+Progress and status specific to this repository is tracked in our
+[project boards](https://github.com/open-telemetry/opentelemetry-go/projects)
+and
+[milestones](https://github.com/open-telemetry/opentelemetry-go/milestones).
+
+Project versioning information and stability guarantees can be found in the
+[versioning documentation](VERSIONING.md).
+
+### Compatibility
+
+OpenTelemetry-Go ensures compatibility with the current supported versions of
+the [Go language](https://golang.org/doc/devel/release#policy):
+
+> Each major Go release is supported until there are two newer major releases.
+> For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release.
+
+For versions of Go that are no longer supported upstream, opentelemetry-go will
+stop ensuring compatibility with these versions in the following manner:
+
+- A minor release of opentelemetry-go will be made to add support for the new
+  supported release of Go.
+- The following minor release of opentelemetry-go will remove compatibility
+  testing for the oldest (now archived upstream) version of Go. This, and
+  future, releases of opentelemetry-go may include features only supported by
+  the currently supported versions of Go.
+
+Currently, this project supports the following environments.
+
+| OS      | Go Version | Architecture |
+|---------|------------|--------------|
+| Ubuntu  | 1.21       | amd64        |
+| Ubuntu  | 1.20       | amd64        |
+| Ubuntu  | 1.21       | 386          |
+| Ubuntu  | 1.20       | 386          |
+| MacOS   | 1.21       | amd64        |
+| MacOS   | 1.20       | amd64        |
+| Windows | 1.21       | amd64        |
+| Windows | 1.20       | amd64        |
+| Windows | 1.21       | 386          |
+| Windows | 1.20       | 386          |
+
+While this project should work for other systems, no compatibility guarantees
+are made for those systems currently.
+
+## Getting Started
+
+You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/go/getting-started/).
+
+OpenTelemetry's goal is to provide a single set of APIs to capture distributed
+traces and metrics from your application and send them to an observability
+platform. This project allows you to do just that for applications written in
+Go. There are two steps to this process: instrument your application, and
+configure an exporter.
+
+### Instrumentation
+
+To start capturing distributed traces and metric events from your application
+it first needs to be instrumented. The easiest way to do this is by using an
+instrumentation library for your code. Be sure to check out [the officially
+supported instrumentation
+libraries](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation).
+
+If you need to extend the telemetry an instrumentation library provides or want
+to build your own instrumentation for your application directly you will need
+to use the
+[Go otel](https://pkg.go.dev/go.opentelemetry.io/otel)
+package. The included [examples](./example/) are a good way to see some
+practical uses of this process.
+
+### Export
+
+Now that your application is instrumented to collect telemetry, it needs an
+export pipeline to send that telemetry to an observability platform.
+
+All officially supported exporters for the OpenTelemetry project are contained in the [exporters directory](./exporters).
+
+| Exporter                              | Metrics | Traces |
+|---------------------------------------|:-------:|:------:|
+| [OTLP](./exporters/otlp/)             |    ✓    |   ✓    |
+| [Prometheus](./exporters/prometheus/) |    ✓    |        |
+| [stdout](./exporters/stdout/)         |    ✓    |   ✓    |
+| [Zipkin](./exporters/zipkin/)         |         |   ✓    |
+
+## Contributing
+
+See the [contributing documentation](CONTRIBUTING.md).

+ 139 - 0
pkg/go.opentelemetry.io/otel/RELEASING.md

@@ -0,0 +1,139 @@
+# Release Process
+
+## Semantic Convention Generation
+
+New versions of the [OpenTelemetry Semantic Conventions] mean new versions of the `semconv` package need to be generated.
+The `semconv-generate` make target is used for this.
+
+1. Checkout a local copy of the [OpenTelemetry Semantic Conventions] to the desired release tag.
+2. Pull the latest `otel/semconvgen` image: `docker pull otel/semconvgen:latest`
+3. Run the `make semconv-generate ...` target from this repository.
+
+For example,
+
+```sh
+export TAG="v1.21.0" # Change to the release version you are generating.
+export OTEL_SEMCONV_REPO="/absolute/path/to/opentelemetry/semantic-conventions"
+docker pull otel/semconvgen:latest
+make semconv-generate # Uses the exported TAG and OTEL_SEMCONV_REPO.
+```
+
+This should create a new sub-package of [`semconv`](./semconv).
+Ensure things look correct before submitting a pull request to include the addition.
+
+## Breaking changes validation
+
+You can run `make gorelease` that runs [gorelease](https://pkg.go.dev/golang.org/x/exp/cmd/gorelease) to ensure that there are no unwanted changes done in the public API.
+
+You can check/report problems with `gorelease` [here](https://golang.org/issues/26420).
+
+## Pre-Release
+
+First, decide which module sets will be released and update their versions
+in `versions.yaml`.  Commit this change to a new branch.
+
+Update go.mod for submodules to depend on the new release which will happen in the next step.
+
+1. Run the `prerelease` make target. It creates a branch
+    `prerelease_<module set>_<new tag>` that will contain all release changes.
+
+    ```
+    make prerelease MODSET=<module set>
+    ```
+
+2. Verify the changes.
+
+    ```
+    git diff ...prerelease_<module set>_<new tag>
+    ```
+
+    This should have changed the version for all modules to be `<new tag>`.
+    If these changes look correct, merge them into your pre-release branch:
+
+    ```go
+    git merge prerelease_<module set>_<new tag>
+    ```
+
+3. Update the [Changelog](./CHANGELOG.md).
+   - Make sure all relevant changes for this release are included and are in language that non-contributors to the project can understand.
+       To verify this, you can look directly at the commits since the `<last tag>`.
+
+       ```
+       git --no-pager log --pretty=oneline "<last tag>..HEAD"
+       ```
+
+   - Move all the `Unreleased` changes into a new section following the title scheme (`[<new tag>] - <date of release>`).
+   - Update all the appropriate links at the bottom.
+
+4. Push the changes to upstream and create a Pull Request on GitHub.
+    Be sure to include the curated changes from the [Changelog](./CHANGELOG.md) in the description.
+
+## Tag
+
+Once the Pull Request with all the version changes has been approved and merged it is time to tag the merged commit.
+
+***IMPORTANT***: It is critical you use the same tag that you used in the Pre-Release step!
+Failure to do so will leave things in a broken state. As long as you do not
+change `versions.yaml` between pre-release and this step, things should be fine.
+
+***IMPORTANT***: [There is currently no way to remove an incorrectly tagged version of a Go module](https://github.com/golang/go/issues/34189).
+It is critical you make sure the version you push upstream is correct.
+[Failure to do so will lead to minor emergencies and tough to work around](https://github.com/open-telemetry/opentelemetry-go/issues/331).
+
+1. For each module set that will be released, run the `add-tags` make target
+    using the `<commit-hash>` of the commit on the main branch for the merged Pull Request.
+
+    ```
+    make add-tags MODSET=<module set> COMMIT=<commit hash>
+    ```
+
+    It should only be necessary to provide an explicit `COMMIT` value if the
+    current `HEAD` of your working directory is not the correct commit.
+
+2. Push tags to the upstream remote (not your fork: `github.com/open-telemetry/opentelemetry-go.git`).
+    Make sure you push all sub-modules as well.
+
+    ```
+    git push upstream <new tag>
+    git push upstream <submodules-path/new tag>
+    ...
+    ```
+
+## Release
+
+Finally create a Release for the new `<new tag>` on GitHub.
+The release body should include all the release notes from the Changelog for this release.
+
+## Verify Examples
+
+After releasing verify that examples build outside of the repository.
+
+```
+./verify_examples.sh
+```
+
+The script copies examples into a different directory removes any `replace` declarations in `go.mod` and builds them.
+This ensures they build with the published release, not the local copy.
+
+## Post-Release
+
+### Contrib Repository
+
+Once verified be sure to [make a release for the `contrib` repository](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/RELEASING.md) that uses this release.
+
+### Website Documentation
+
+Update the [Go instrumentation documentation] in the OpenTelemetry website under [content/en/docs/instrumentation/go].
+Importantly, bump any package versions referenced to be the latest one you just released and ensure all code examples still compile and are accurate.
+
+[OpenTelemetry Semantic Conventions]: https://github.com/open-telemetry/semantic-conventions
+[Go instrumentation documentation]: https://opentelemetry.io/docs/instrumentation/go/
+[content/en/docs/instrumentation/go]: https://github.com/open-telemetry/opentelemetry.io/tree/main/content/en/docs/instrumentation/go
+
+### Demo Repository
+
+Bump the dependencies in the following Go services:
+
+- [`accountingservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/accountingservice)
+- [`checkoutservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/checkoutservice)
+- [`productcatalogservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/productcatalogservice)

+ 224 - 0
pkg/go.opentelemetry.io/otel/VERSIONING.md

@@ -0,0 +1,224 @@
+# Versioning
+
+This document describes the versioning policy for this repository. This policy
+is designed so the following goals can be achieved.
+
+**Users are provided a codebase of value that is stable and secure.**
+
+## Policy
+
+* Versioning of this project will be idiomatic of a Go project using [Go
+  modules](https://github.com/golang/go/wiki/Modules).
+  * [Semantic import
+    versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning)
+    will be used.
+    * Versions will comply with [semver
+      2.0](https://semver.org/spec/v2.0.0.html) with the following exceptions.
+      * New methods may be added to exported API interfaces. All exported
+        interfaces that fall within this exception will include the following
+        paragraph in their public documentation.
+
+        > Warning: methods may be added to this interface in minor releases.
+
+    * If a module is version `v2` or higher, the major version of the module
+      must be included as a `/vN` at the end of the module paths used in
+      `go.mod` files (e.g., `module go.opentelemetry.io/otel/v2`, `require
+      go.opentelemetry.io/otel/v2 v2.0.1`) and in the package import path
+      (e.g., `import "go.opentelemetry.io/otel/v2/trace"`). This includes the
+      paths used in `go get` commands (e.g., `go get
+      go.opentelemetry.io/otel/[email protected]`.  Note there is both a `/v2` and a
+      `@v2.0.1` in that example. One way to think about it is that the module
+      name now includes the `/v2`, so include `/v2` whenever you are using the
+      module name).
+    * If a module is version `v0` or `v1`, do not include the major version in
+      either the module path or the import path.
+  * Modules will be used to encapsulate signals and components.
+    * Experimental modules still under active development will be versioned at
+      `v0` to imply the stability guarantee defined by
+      [semver](https://semver.org/spec/v2.0.0.html#spec-item-4).
+
+      > Major version zero (0.y.z) is for initial development. Anything MAY
+      > change at any time. The public API SHOULD NOT be considered stable.
+
+    * Mature modules for which we guarantee a stable public API will be versioned
+      with a major version greater than `v0`.
+      * The decision to make a module stable will be made on a case-by-case
+        basis by the maintainers of this project.
+    * Experimental modules will start their versioning at `v0.0.0` and will
+      increment their minor version when backwards incompatible changes are
+      released and increment their patch version when backwards compatible
+      changes are released.
+    * All stable modules that use the same major version number will use the
+      same entire version number.
+      * Stable modules may be released with an incremented minor or patch
+        version even though that module has not been changed, but rather so
+        that it will remain at the same version as other stable modules that
+        did undergo change.
+      * When an experimental module becomes stable a new stable module version
+        will be released and will include this now stable module. The new
+        stable module version will be an increment of the minor version number
+        and will be applied to all existing stable modules as well as the newly
+        stable module being released.
+* Versioning of the associated [contrib
+  repository](https://github.com/open-telemetry/opentelemetry-go-contrib) of
+  this project will be idiomatic of a Go project using [Go
+  modules](https://github.com/golang/go/wiki/Modules).
+  * [Semantic import
+    versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning)
+    will be used.
+    * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html).
+    * If a module is version `v2` or higher, the
+      major version of the module must be included as a `/vN` at the end of the
+      module paths used in `go.mod` files (e.g., `module
+      go.opentelemetry.io/contrib/instrumentation/host/v2`, `require
+      go.opentelemetry.io/contrib/instrumentation/host/v2 v2.0.1`) and in the
+      package import path (e.g., `import
+      "go.opentelemetry.io/contrib/instrumentation/host/v2"`). This includes
+      the paths used in `go get` commands (e.g., `go get
+      go.opentelemetry.io/contrib/instrumentation/host/[email protected]`.  Note there
+      is both a `/v2` and a `@v2.0.1` in that example. One way to think about
+      it is that the module name now includes the `/v2`, so include `/v2`
+      whenever you are using the module name).
+    * If a module is version `v0` or `v1`, do not include the major version
+      in either the module path or the import path.
+  * In addition to public APIs, telemetry produced by stable instrumentation
+    will remain stable and backwards compatible. This is to avoid breaking
+    alerts and dashboard.
+  * Modules will be used to encapsulate instrumentation, detectors, exporters,
+    propagators, and any other independent sets of related components.
+    * Experimental modules still under active development will be versioned at
+      `v0` to imply the stability guarantee defined by
+      [semver](https://semver.org/spec/v2.0.0.html#spec-item-4).
+
+      > Major version zero (0.y.z) is for initial development. Anything MAY
+      > change at any time. The public API SHOULD NOT be considered stable.
+
+    * Mature modules for which we guarantee a stable public API and telemetry will
+      be versioned with a major version greater than `v0`.
+    * Experimental modules will start their versioning at `v0.0.0` and will
+      increment their minor version when backwards incompatible changes are
+      released and increment their patch version when backwards compatible
+      changes are released.
+    * Stable contrib modules cannot depend on experimental modules from this
+      project.
+    * All stable contrib modules of the same major version with this project
+      will use the same entire version as this project.
+      * Stable modules may be released with an incremented minor or patch
+        version even though that module's code has not been changed. Instead
+        the only change that will have been included is to have updated that
+        modules dependency on this project's stable APIs.
+      * When an experimental module in contrib becomes stable a new stable
+        module version will be released and will include this now stable
+        module. The new stable module version will be an increment of the minor
+        version number and will be applied to all existing stable contrib
+        modules, this project's modules, and the newly stable module being
+        released.
+  * Contrib modules will be kept up to date with this project's releases.
+    * Due to the dependency contrib modules will implicitly have on this
+      project's modules the release of stable contrib modules to match the
+      released version number will be staggered after this project's release.
+      There is no explicit time guarantee for how long after this projects
+      release the contrib release will be. Effort should be made to keep them
+      as close in time as possible.
+    * No additional stable release in this project can be made until the
+      contrib repository has a matching stable release.
+    * No release can be made in the contrib repository after this project's
+      stable release except for a stable release of the contrib repository.
+* GitHub releases will be made for all releases.
+* Go modules will be made available at Go package mirrors.
+
+## Example Versioning Lifecycle
+
+To better understand the implementation of the above policy the following
+example is provided. This project is simplified to include only the following
+modules and their versions:
+
+* `otel`: `v0.14.0`
+* `otel/trace`: `v0.14.0`
+* `otel/metric`: `v0.14.0`
+* `otel/baggage`: `v0.14.0`
+* `otel/sdk/trace`: `v0.14.0`
+* `otel/sdk/metric`: `v0.14.0`
+
+These modules have been developed to a point where the `otel/trace`,
+`otel/baggage`, and `otel/sdk/trace` modules have reached a point that they
+should be considered for a stable release. The `otel/metric` and
+`otel/sdk/metric` are still under active development and the `otel` module
+depends on both `otel/trace` and `otel/metric`.
+
+The `otel` package is refactored to remove its dependencies on `otel/metric` so
+it can be released as stable as well. With that done the following release
+candidates are made:
+
+* `otel`: `v1.0.0-RC1`
+* `otel/trace`: `v1.0.0-RC1`
+* `otel/baggage`: `v1.0.0-RC1`
+* `otel/sdk/trace`: `v1.0.0-RC1`
+
+The `otel/metric` and `otel/sdk/metric` modules remain at `v0.14.0`.
+
+A few minor issues are discovered in the `otel/trace` package. These issues are
+resolved with some minor, but backwards incompatible, changes and are released
+as a second release candidate:
+
+* `otel`: `v1.0.0-RC2`
+* `otel/trace`: `v1.0.0-RC2`
+* `otel/baggage`: `v1.0.0-RC2`
+* `otel/sdk/trace`: `v1.0.0-RC2`
+
+Notice that all module version numbers are incremented to adhere to our
+versioning policy.
+
+After these release candidates have been evaluated to satisfaction, they are
+released as version `v1.0.0`.
+
+* `otel`: `v1.0.0`
+* `otel/trace`: `v1.0.0`
+* `otel/baggage`: `v1.0.0`
+* `otel/sdk/trace`: `v1.0.0`
+
+Since both the `go` utility and the Go module system support [the semantic
+versioning definition of
+precedence](https://semver.org/spec/v2.0.0.html#spec-item-11), this release
+will correctly be interpreted as the successor to the previous release
+candidates.
+
+Active development of this project continues. The `otel/metric` module now has
+backwards incompatible changes to its API that need to be released and the
+`otel/baggage` module has a minor bug fix that needs to be released. The
+following release is made:
+
+* `otel`: `v1.0.1`
+* `otel/trace`: `v1.0.1`
+* `otel/metric`: `v0.15.0`
+* `otel/baggage`: `v1.0.1`
+* `otel/sdk/trace`: `v1.0.1`
+* `otel/sdk/metric`: `v0.15.0`
+
+Notice that, again, all stable module versions are incremented in unison and
+the `otel/sdk/metric` package, which depends on the `otel/metric` package, also
+bumped its version. This bump of the `otel/sdk/metric` package makes sense
+given their coupling, though it is not explicitly required by our versioning
+policy.
+
+As we progress, the `otel/metric` and `otel/sdk/metric` packages have reached a
+point where they should be evaluated for stability. The `otel` module is
+reintegrated with the `otel/metric` package and the following release is made:
+
+* `otel`: `v1.1.0-RC1`
+* `otel/trace`: `v1.1.0-RC1`
+* `otel/metric`: `v1.1.0-RC1`
+* `otel/baggage`: `v1.1.0-RC1`
+* `otel/sdk/trace`: `v1.1.0-RC1`
+* `otel/sdk/metric`: `v1.1.0-RC1`
+
+All the modules are evaluated and determined to a viable stable release. They
+are then released as version `v1.1.0` (the minor version is incremented to
+indicate the addition of new signal).
+
+* `otel`: `v1.1.0`
+* `otel/trace`: `v1.1.0`
+* `otel/metric`: `v1.1.0`
+* `otel/baggage`: `v1.1.0`
+* `otel/sdk/trace`: `v1.1.0`
+* `otel/sdk/metric`: `v1.1.0`

+ 284 - 0
pkg/go.opentelemetry.io/otel/attribute/benchmark_test.go

@@ -0,0 +1,284 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute_test
+
+import (
+	"testing"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+// Store results in a file scope var to ensure compiler does not optimize the
+// test away.
+var (
+	outV  attribute.Value
+	outKV attribute.KeyValue
+
+	outBool         bool
+	outBoolSlice    []bool
+	outInt64        int64
+	outInt64Slice   []int64
+	outFloat64      float64
+	outFloat64Slice []float64
+	outStr          string
+	outStrSlice     []string
+)
+
+func benchmarkEmit(kv attribute.KeyValue) func(*testing.B) {
+	return func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outStr = kv.Value.Emit()
+		}
+	}
+}
+
+func BenchmarkBool(b *testing.B) {
+	k, v := "bool", true
+	kv := attribute.Bool(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.BoolValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.Bool(k, v)
+		}
+	})
+	b.Run("AsBool", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outBool = kv.Value.AsBool()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkBoolSlice(b *testing.B) {
+	k, v := "bool slice", []bool{true, false, true}
+	kv := attribute.BoolSlice(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.BoolSliceValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.BoolSlice(k, v)
+		}
+	})
+	b.Run("AsBoolSlice", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outBoolSlice = kv.Value.AsBoolSlice()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkInt(b *testing.B) {
+	k, v := "int", int(42)
+	kv := attribute.Int(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.IntValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.Int(k, v)
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkIntSlice(b *testing.B) {
+	k, v := "int slice", []int{42, -3, 12}
+	kv := attribute.IntSlice(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.IntSliceValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.IntSlice(k, v)
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkInt64(b *testing.B) {
+	k, v := "int64", int64(42)
+	kv := attribute.Int64(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.Int64Value(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.Int64(k, v)
+		}
+	})
+	b.Run("AsInt64", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outInt64 = kv.Value.AsInt64()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkInt64Slice(b *testing.B) {
+	k, v := "int64 slice", []int64{42, -3, 12}
+	kv := attribute.Int64Slice(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.Int64SliceValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.Int64Slice(k, v)
+		}
+	})
+	b.Run("AsInt64Slice", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outInt64Slice = kv.Value.AsInt64Slice()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkFloat64(b *testing.B) {
+	k, v := "float64", float64(42)
+	kv := attribute.Float64(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.Float64Value(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.Float64(k, v)
+		}
+	})
+	b.Run("AsFloat64", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outFloat64 = kv.Value.AsFloat64()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkFloat64Slice(b *testing.B) {
+	k, v := "float64 slice", []float64{42, -3, 12}
+	kv := attribute.Float64Slice(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.Float64SliceValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.Float64Slice(k, v)
+		}
+	})
+	b.Run("AsFloat64Slice", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outFloat64Slice = kv.Value.AsFloat64Slice()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkString(b *testing.B) {
+	k, v := "string", "42"
+	kv := attribute.String(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.StringValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.String(k, v)
+		}
+	})
+	b.Run("AsString", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outStr = kv.Value.AsString()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}
+
+func BenchmarkStringSlice(b *testing.B) {
+	k, v := "float64 slice", []string{"forty-two", "negative three", "twelve"}
+	kv := attribute.StringSlice(k, v)
+
+	b.Run("Value", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outV = attribute.StringSliceValue(v)
+		}
+	})
+	b.Run("KeyValue", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outKV = attribute.StringSlice(k, v)
+		}
+	})
+	b.Run("AsStringSlice", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			outStrSlice = kv.Value.AsStringSlice()
+		}
+	})
+	b.Run("Emit", benchmarkEmit(kv))
+}

+ 16 - 0
pkg/go.opentelemetry.io/otel/attribute/doc.go

@@ -0,0 +1,16 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package attribute provides key and value attributes.
+package attribute // import "go.opentelemetry.io/otel/attribute"

+ 146 - 0
pkg/go.opentelemetry.io/otel/attribute/encoder.go

@@ -0,0 +1,146 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute // import "go.opentelemetry.io/otel/attribute"
+
+import (
+	"bytes"
+	"sync"
+	"sync/atomic"
+)
+
+type (
+	// Encoder is a mechanism for serializing an attribute set into a specific
+	// string representation that supports caching, to avoid repeated
+	// serialization. An example could be an exporter encoding the attribute
+	// set into a wire representation.
+	Encoder interface {
+		// Encode returns the serialized encoding of the attribute set using
+		// its Iterator. This result may be cached by a attribute.Set.
+		Encode(iterator Iterator) string
+
+		// ID returns a value that is unique for each class of attribute
+		// encoder. Attribute encoders allocate these using `NewEncoderID`.
+		ID() EncoderID
+	}
+
+	// EncoderID is used to identify distinct Encoder
+	// implementations, for caching encoded results.
+	EncoderID struct {
+		value uint64
+	}
+
+	// defaultAttrEncoder uses a sync.Pool of buffers to reduce the number of
+	// allocations used in encoding attributes. This implementation encodes a
+	// comma-separated list of key=value, with '/'-escaping of '=', ',', and
+	// '\'.
+	defaultAttrEncoder struct {
+		// pool is a pool of attribute set builders. The buffers in this pool
+		// grow to a size that most attribute encodings will not allocate new
+		// memory.
+		pool sync.Pool // *bytes.Buffer
+	}
+)
+
+// escapeChar is used to ensure uniqueness of the attribute encoding where
+// keys or values contain either '=' or ','.  Since there is no parser needed
+// for this encoding and its only requirement is to be unique, this choice is
+// arbitrary.  Users will see these in some exporters (e.g., stdout), so the
+// backslash ('\') is used as a conventional choice.
+const escapeChar = '\\'
+
+var (
+	_ Encoder = &defaultAttrEncoder{}
+
+	// encoderIDCounter is for generating IDs for other attribute encoders.
+	encoderIDCounter uint64
+
+	defaultEncoderOnce     sync.Once
+	defaultEncoderID       = NewEncoderID()
+	defaultEncoderInstance *defaultAttrEncoder
+)
+
+// NewEncoderID returns a unique attribute encoder ID. It should be called
+// once per each type of attribute encoder. Preferably in init() or in var
+// definition.
+func NewEncoderID() EncoderID {
+	return EncoderID{value: atomic.AddUint64(&encoderIDCounter, 1)}
+}
+
+// DefaultEncoder returns an attribute encoder that encodes attributes in such
+// a way that each escaped attribute's key is followed by an equal sign and
+// then by an escaped attribute's value. All key-value pairs are separated by
+// a comma.
+//
+// Escaping is done by prepending a backslash before either a backslash, equal
+// sign or a comma.
+func DefaultEncoder() Encoder {
+	defaultEncoderOnce.Do(func() {
+		defaultEncoderInstance = &defaultAttrEncoder{
+			pool: sync.Pool{
+				New: func() interface{} {
+					return &bytes.Buffer{}
+				},
+			},
+		}
+	})
+	return defaultEncoderInstance
+}
+
+// Encode is a part of an implementation of the AttributeEncoder interface.
+func (d *defaultAttrEncoder) Encode(iter Iterator) string {
+	buf := d.pool.Get().(*bytes.Buffer)
+	defer d.pool.Put(buf)
+	buf.Reset()
+
+	for iter.Next() {
+		i, keyValue := iter.IndexedAttribute()
+		if i > 0 {
+			_, _ = buf.WriteRune(',')
+		}
+		copyAndEscape(buf, string(keyValue.Key))
+
+		_, _ = buf.WriteRune('=')
+
+		if keyValue.Value.Type() == STRING {
+			copyAndEscape(buf, keyValue.Value.AsString())
+		} else {
+			_, _ = buf.WriteString(keyValue.Value.Emit())
+		}
+	}
+	return buf.String()
+}
+
+// ID is a part of an implementation of the AttributeEncoder interface.
+func (*defaultAttrEncoder) ID() EncoderID {
+	return defaultEncoderID
+}
+
+// copyAndEscape escapes `=`, `,` and its own escape character (`\`),
+// making the default encoding unique.
+func copyAndEscape(buf *bytes.Buffer, val string) {
+	for _, ch := range val {
+		switch ch {
+		case '=', ',', escapeChar:
+			_, _ = buf.WriteRune(escapeChar)
+		}
+		_, _ = buf.WriteRune(ch)
+	}
+}
+
+// Valid returns true if this encoder ID was allocated by
+// `NewEncoderID`.  Invalid encoder IDs will not be cached.
+func (id EncoderID) Valid() bool {
+	return id.value != 0
+}

+ 60 - 0
pkg/go.opentelemetry.io/otel/attribute/filter.go

@@ -0,0 +1,60 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute // import "go.opentelemetry.io/otel/attribute"
+
+// Filter supports removing certain attributes from attribute sets. When
+// the filter returns true, the attribute will be kept in the filtered
+// attribute set. When the filter returns false, the attribute is excluded
+// from the filtered attribute set, and the attribute instead appears in
+// the removed list of excluded attributes.
+type Filter func(KeyValue) bool
+
+// NewAllowKeysFilter returns a Filter that only allows attributes with one of
+// the provided keys.
+//
+// If keys is empty a deny-all filter is returned.
+func NewAllowKeysFilter(keys ...Key) Filter {
+	if len(keys) <= 0 {
+		return func(kv KeyValue) bool { return false }
+	}
+
+	allowed := make(map[Key]struct{})
+	for _, k := range keys {
+		allowed[k] = struct{}{}
+	}
+	return func(kv KeyValue) bool {
+		_, ok := allowed[kv.Key]
+		return ok
+	}
+}
+
+// NewDenyKeysFilter returns a Filter that only allows attributes
+// that do not have one of the provided keys.
+//
+// If keys is empty an allow-all filter is returned.
+func NewDenyKeysFilter(keys ...Key) Filter {
+	if len(keys) <= 0 {
+		return func(kv KeyValue) bool { return true }
+	}
+
+	forbid := make(map[Key]struct{})
+	for _, k := range keys {
+		forbid[k] = struct{}{}
+	}
+	return func(kv KeyValue) bool {
+		_, ok := forbid[kv.Key]
+		return !ok
+	}
+}

+ 87 - 0
pkg/go.opentelemetry.io/otel/attribute/filter_test.go

@@ -0,0 +1,87 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute
+
+import "testing"
+
+func TestNewAllowKeysFilter(t *testing.T) {
+	keys := []string{"zero", "one", "two"}
+	attrs := []KeyValue{Int(keys[0], 0), Int(keys[1], 1), Int(keys[2], 2)}
+
+	t.Run("Empty", func(t *testing.T) {
+		empty := NewAllowKeysFilter()
+		for _, kv := range attrs {
+			if empty(kv) {
+				t.Errorf("empty NewAllowKeysFilter filter accepted %v", kv)
+			}
+		}
+	})
+
+	t.Run("Partial", func(t *testing.T) {
+		partial := NewAllowKeysFilter(Key(keys[0]), Key(keys[1]))
+		for _, kv := range attrs[:2] {
+			if !partial(kv) {
+				t.Errorf("partial NewAllowKeysFilter filter denied %v", kv)
+			}
+		}
+		if partial(attrs[2]) {
+			t.Errorf("partial NewAllowKeysFilter filter accepted %v", attrs[2])
+		}
+	})
+
+	t.Run("Full", func(t *testing.T) {
+		full := NewAllowKeysFilter(Key(keys[0]), Key(keys[1]), Key(keys[2]))
+		for _, kv := range attrs {
+			if !full(kv) {
+				t.Errorf("full NewAllowKeysFilter filter denied %v", kv)
+			}
+		}
+	})
+}
+
+func TestNewDenyKeysFilter(t *testing.T) {
+	keys := []string{"zero", "one", "two"}
+	attrs := []KeyValue{Int(keys[0], 0), Int(keys[1], 1), Int(keys[2], 2)}
+
+	t.Run("Empty", func(t *testing.T) {
+		empty := NewDenyKeysFilter()
+		for _, kv := range attrs {
+			if !empty(kv) {
+				t.Errorf("empty NewDenyKeysFilter filter denied %v", kv)
+			}
+		}
+	})
+
+	t.Run("Partial", func(t *testing.T) {
+		partial := NewDenyKeysFilter(Key(keys[0]), Key(keys[1]))
+		for _, kv := range attrs[:2] {
+			if partial(kv) {
+				t.Errorf("partial NewDenyKeysFilter filter accepted %v", kv)
+			}
+		}
+		if !partial(attrs[2]) {
+			t.Errorf("partial NewDenyKeysFilter filter denied %v", attrs[2])
+		}
+	})
+
+	t.Run("Full", func(t *testing.T) {
+		full := NewDenyKeysFilter(Key(keys[0]), Key(keys[1]), Key(keys[2]))
+		for _, kv := range attrs {
+			if full(kv) {
+				t.Errorf("full NewDenyKeysFilter filter accepted %v", kv)
+			}
+		}
+	})
+}

+ 161 - 0
pkg/go.opentelemetry.io/otel/attribute/iterator.go

@@ -0,0 +1,161 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute // import "go.opentelemetry.io/otel/attribute"
+
+// Iterator allows iterating over the set of attributes in order, sorted by
+// key.
+type Iterator struct {
+	storage *Set
+	idx     int
+}
+
+// MergeIterator supports iterating over two sets of attributes while
+// eliminating duplicate values from the combined set. The first iterator
+// value takes precedence.
+type MergeIterator struct {
+	one     oneIterator
+	two     oneIterator
+	current KeyValue
+}
+
+type oneIterator struct {
+	iter Iterator
+	done bool
+	attr KeyValue
+}
+
+// Next moves the iterator to the next position. Returns false if there are no
+// more attributes.
+func (i *Iterator) Next() bool {
+	i.idx++
+	return i.idx < i.Len()
+}
+
+// Label returns current KeyValue. Must be called only after Next returns
+// true.
+//
+// Deprecated: Use Attribute instead.
+func (i *Iterator) Label() KeyValue {
+	return i.Attribute()
+}
+
+// Attribute returns the current KeyValue of the Iterator. It must be called
+// only after Next returns true.
+func (i *Iterator) Attribute() KeyValue {
+	kv, _ := i.storage.Get(i.idx)
+	return kv
+}
+
+// IndexedLabel returns current index and attribute. Must be called only
+// after Next returns true.
+//
+// Deprecated: Use IndexedAttribute instead.
+func (i *Iterator) IndexedLabel() (int, KeyValue) {
+	return i.idx, i.Attribute()
+}
+
+// IndexedAttribute returns current index and attribute. Must be called only
+// after Next returns true.
+func (i *Iterator) IndexedAttribute() (int, KeyValue) {
+	return i.idx, i.Attribute()
+}
+
+// Len returns a number of attributes in the iterated set.
+func (i *Iterator) Len() int {
+	return i.storage.Len()
+}
+
+// ToSlice is a convenience function that creates a slice of attributes from
+// the passed iterator. The iterator is set up to start from the beginning
+// before creating the slice.
+func (i *Iterator) ToSlice() []KeyValue {
+	l := i.Len()
+	if l == 0 {
+		return nil
+	}
+	i.idx = -1
+	slice := make([]KeyValue, 0, l)
+	for i.Next() {
+		slice = append(slice, i.Attribute())
+	}
+	return slice
+}
+
+// NewMergeIterator returns a MergeIterator for merging two attribute sets.
+// Duplicates are resolved by taking the value from the first set.
+func NewMergeIterator(s1, s2 *Set) MergeIterator {
+	mi := MergeIterator{
+		one: makeOne(s1.Iter()),
+		two: makeOne(s2.Iter()),
+	}
+	return mi
+}
+
+func makeOne(iter Iterator) oneIterator {
+	oi := oneIterator{
+		iter: iter,
+	}
+	oi.advance()
+	return oi
+}
+
+func (oi *oneIterator) advance() {
+	if oi.done = !oi.iter.Next(); !oi.done {
+		oi.attr = oi.iter.Attribute()
+	}
+}
+
+// Next returns true if there is another attribute available.
+func (m *MergeIterator) Next() bool {
+	if m.one.done && m.two.done {
+		return false
+	}
+	if m.one.done {
+		m.current = m.two.attr
+		m.two.advance()
+		return true
+	}
+	if m.two.done {
+		m.current = m.one.attr
+		m.one.advance()
+		return true
+	}
+	if m.one.attr.Key == m.two.attr.Key {
+		m.current = m.one.attr // first iterator attribute value wins
+		m.one.advance()
+		m.two.advance()
+		return true
+	}
+	if m.one.attr.Key < m.two.attr.Key {
+		m.current = m.one.attr
+		m.one.advance()
+		return true
+	}
+	m.current = m.two.attr
+	m.two.advance()
+	return true
+}
+
+// Label returns the current value after Next() returns true.
+//
+// Deprecated: Use Attribute instead.
+func (m *MergeIterator) Label() KeyValue {
+	return m.current
+}
+
+// Attribute returns the current value after Next() returns true.
+func (m *MergeIterator) Attribute() KeyValue {
+	return m.current
+}

+ 148 - 0
pkg/go.opentelemetry.io/otel/attribute/iterator_test.go

@@ -0,0 +1,148 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute_test
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+func TestIterator(t *testing.T) {
+	one := attribute.String("one", "1")
+	two := attribute.Int("two", 2)
+	lbl := attribute.NewSet(one, two)
+	iter := lbl.Iter()
+	require.Equal(t, 2, iter.Len())
+
+	require.True(t, iter.Next())
+	require.Equal(t, one, iter.Attribute())
+	idx, attr := iter.IndexedAttribute()
+	require.Equal(t, 0, idx)
+	require.Equal(t, one, attr)
+	require.Equal(t, 2, iter.Len())
+
+	require.True(t, iter.Next())
+	require.Equal(t, two, iter.Attribute())
+	idx, attr = iter.IndexedAttribute()
+	require.Equal(t, 1, idx)
+	require.Equal(t, two, attr)
+	require.Equal(t, 2, iter.Len())
+
+	require.False(t, iter.Next())
+	require.Equal(t, 2, iter.Len())
+}
+
+func TestEmptyIterator(t *testing.T) {
+	lbl := attribute.NewSet()
+	iter := lbl.Iter()
+	require.Equal(t, 0, iter.Len())
+	require.False(t, iter.Next())
+}
+
+func TestMergedIterator(t *testing.T) {
+	type inputs struct {
+		name   string
+		keys1  []string
+		keys2  []string
+		expect []string
+	}
+
+	makeAttributes := func(keys []string, num int) (result []attribute.KeyValue) {
+		for _, k := range keys {
+			result = append(result, attribute.Int(k, num))
+		}
+		return
+	}
+
+	for _, input := range []inputs{
+		{
+			name:   "one overlap",
+			keys1:  []string{"A", "B"},
+			keys2:  []string{"B", "C"},
+			expect: []string{"A/1", "B/1", "C/2"},
+		},
+		{
+			name:   "reversed one overlap",
+			keys1:  []string{"B", "A"},
+			keys2:  []string{"C", "B"},
+			expect: []string{"A/1", "B/1", "C/2"},
+		},
+		{
+			name:   "one empty",
+			keys1:  nil,
+			keys2:  []string{"C", "B"},
+			expect: []string{"B/2", "C/2"},
+		},
+		{
+			name:   "two empty",
+			keys1:  []string{"C", "B"},
+			keys2:  nil,
+			expect: []string{"B/1", "C/1"},
+		},
+		{
+			name:   "no overlap both",
+			keys1:  []string{"C"},
+			keys2:  []string{"B"},
+			expect: []string{"B/2", "C/1"},
+		},
+		{
+			name:   "one empty single two",
+			keys1:  nil,
+			keys2:  []string{"B"},
+			expect: []string{"B/2"},
+		},
+		{
+			name:   "two empty single one",
+			keys1:  []string{"A"},
+			keys2:  nil,
+			expect: []string{"A/1"},
+		},
+		{
+			name:   "all empty",
+			keys1:  nil,
+			keys2:  nil,
+			expect: nil,
+		},
+		{
+			name:   "full overlap",
+			keys1:  []string{"A", "B", "C", "D"},
+			keys2:  []string{"A", "B", "C", "D"},
+			expect: []string{"A/1", "B/1", "C/1", "D/1"},
+		},
+	} {
+		t.Run(input.name, func(t *testing.T) {
+			attr1 := makeAttributes(input.keys1, 1)
+			attr2 := makeAttributes(input.keys2, 2)
+
+			set1 := attribute.NewSet(attr1...)
+			set2 := attribute.NewSet(attr2...)
+
+			merge := attribute.NewMergeIterator(&set1, &set2)
+
+			var result []string
+
+			for merge.Next() {
+				attr := merge.Attribute()
+				result = append(result, fmt.Sprint(attr.Key, "/", attr.Value.Emit()))
+			}
+
+			require.Equal(t, input.expect, result)
+		})
+	}
+}

+ 134 - 0
pkg/go.opentelemetry.io/otel/attribute/key.go

@@ -0,0 +1,134 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute // import "go.opentelemetry.io/otel/attribute"
+
+// Key represents the key part in key-value pairs. It's a string. The
+// allowed character set in the key depends on the use of the key.
+type Key string
+
+// Bool creates a KeyValue instance with a BOOL Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- Bool(name, value).
+func (k Key) Bool(v bool) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: BoolValue(v),
+	}
+}
+
+// BoolSlice creates a KeyValue instance with a BOOLSLICE Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- BoolSlice(name, value).
+func (k Key) BoolSlice(v []bool) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: BoolSliceValue(v),
+	}
+}
+
+// Int creates a KeyValue instance with an INT64 Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- Int(name, value).
+func (k Key) Int(v int) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: IntValue(v),
+	}
+}
+
+// IntSlice creates a KeyValue instance with an INT64SLICE Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- IntSlice(name, value).
+func (k Key) IntSlice(v []int) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: IntSliceValue(v),
+	}
+}
+
+// Int64 creates a KeyValue instance with an INT64 Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- Int64(name, value).
+func (k Key) Int64(v int64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Int64Value(v),
+	}
+}
+
+// Int64Slice creates a KeyValue instance with an INT64SLICE Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- Int64Slice(name, value).
+func (k Key) Int64Slice(v []int64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Int64SliceValue(v),
+	}
+}
+
+// Float64 creates a KeyValue instance with a FLOAT64 Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- Float64(name, value).
+func (k Key) Float64(v float64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Float64Value(v),
+	}
+}
+
+// Float64Slice creates a KeyValue instance with a FLOAT64SLICE Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- Float64(name, value).
+func (k Key) Float64Slice(v []float64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Float64SliceValue(v),
+	}
+}
+
+// String creates a KeyValue instance with a STRING Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- String(name, value).
+func (k Key) String(v string) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: StringValue(v),
+	}
+}
+
+// StringSlice creates a KeyValue instance with a STRINGSLICE Value.
+//
+// If creating both a key and value at the same time, use the provided
+// convenience function instead -- StringSlice(name, value).
+func (k Key) StringSlice(v []string) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: StringSliceValue(v),
+	}
+}
+
+// Defined returns true for non-empty keys.
+func (k Key) Defined() bool {
+	return len(k) != 0
+}

+ 101 - 0
pkg/go.opentelemetry.io/otel/attribute/key_test.go

@@ -0,0 +1,101 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute_test
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+func TestDefined(t *testing.T) {
+	for _, testcase := range []struct {
+		name string
+		k    attribute.Key
+		want bool
+	}{
+		{
+			name: "Key.Defined() returns true when len(v.Name) != 0",
+			k:    attribute.Key("foo"),
+			want: true,
+		},
+		{
+			name: "Key.Defined() returns false when len(v.Name) == 0",
+			k:    attribute.Key(""),
+			want: false,
+		},
+	} {
+		t.Run(testcase.name, func(t *testing.T) {
+			//func (k attribute.Key) Defined() bool {
+			have := testcase.k.Defined()
+			if have != testcase.want {
+				t.Errorf("Want: %v, but have: %v", testcase.want, have)
+			}
+		})
+	}
+}
+
+func TestJSONValue(t *testing.T) {
+	var kvs interface{} = [2]attribute.KeyValue{
+		attribute.String("A", "B"),
+		attribute.Int64("C", 1),
+	}
+
+	data, err := json.Marshal(kvs)
+	require.NoError(t, err)
+	require.Equal(t,
+		`[{"Key":"A","Value":{"Type":"STRING","Value":"B"}},{"Key":"C","Value":{"Type":"INT64","Value":1}}]`,
+		string(data))
+}
+
+func TestEmit(t *testing.T) {
+	for _, testcase := range []struct {
+		name string
+		v    attribute.Value
+		want string
+	}{
+		{
+			name: `test Key.Emit() can emit a string representing self.BOOL`,
+			v:    attribute.BoolValue(true),
+			want: "true",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.INT64`,
+			v:    attribute.Int64Value(42),
+			want: "42",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.FLOAT64`,
+			v:    attribute.Float64Value(42.1),
+			want: "42.1",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.STRING`,
+			v:    attribute.StringValue("foo"),
+			want: "foo",
+		},
+	} {
+		t.Run(testcase.name, func(t *testing.T) {
+			//proto: func (v attribute.Value) Emit() string {
+			have := testcase.v.Emit()
+			if have != testcase.want {
+				t.Errorf("Want: %s, but have: %s", testcase.want, have)
+			}
+		})
+	}
+}

+ 86 - 0
pkg/go.opentelemetry.io/otel/attribute/kv.go

@@ -0,0 +1,86 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute // import "go.opentelemetry.io/otel/attribute"
+
+import (
+	"fmt"
+)
+
+// KeyValue holds a key and value pair.
+type KeyValue struct {
+	Key   Key
+	Value Value
+}
+
+// Valid returns if kv is a valid OpenTelemetry attribute.
+func (kv KeyValue) Valid() bool {
+	return kv.Key.Defined() && kv.Value.Type() != INVALID
+}
+
+// Bool creates a KeyValue with a BOOL Value type.
+func Bool(k string, v bool) KeyValue {
+	return Key(k).Bool(v)
+}
+
+// BoolSlice creates a KeyValue with a BOOLSLICE Value type.
+func BoolSlice(k string, v []bool) KeyValue {
+	return Key(k).BoolSlice(v)
+}
+
+// Int creates a KeyValue with an INT64 Value type.
+func Int(k string, v int) KeyValue {
+	return Key(k).Int(v)
+}
+
+// IntSlice creates a KeyValue with an INT64SLICE Value type.
+func IntSlice(k string, v []int) KeyValue {
+	return Key(k).IntSlice(v)
+}
+
+// Int64 creates a KeyValue with an INT64 Value type.
+func Int64(k string, v int64) KeyValue {
+	return Key(k).Int64(v)
+}
+
+// Int64Slice creates a KeyValue with an INT64SLICE Value type.
+func Int64Slice(k string, v []int64) KeyValue {
+	return Key(k).Int64Slice(v)
+}
+
+// Float64 creates a KeyValue with a FLOAT64 Value type.
+func Float64(k string, v float64) KeyValue {
+	return Key(k).Float64(v)
+}
+
+// Float64Slice creates a KeyValue with a FLOAT64SLICE Value type.
+func Float64Slice(k string, v []float64) KeyValue {
+	return Key(k).Float64Slice(v)
+}
+
+// String creates a KeyValue with a STRING Value type.
+func String(k, v string) KeyValue {
+	return Key(k).String(v)
+}
+
+// StringSlice creates a KeyValue with a STRINGSLICE Value type.
+func StringSlice(k string, v []string) KeyValue {
+	return Key(k).StringSlice(v)
+}
+
+// Stringer creates a new key-value pair with a passed name and a string
+// value generated by the passed Stringer interface.
+func Stringer(k string, v fmt.Stringer) KeyValue {
+	return Key(k).String(v.String())
+}

+ 182 - 0
pkg/go.opentelemetry.io/otel/attribute/kv_test.go

@@ -0,0 +1,182 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute_test
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/stretchr/testify/assert"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+func TestKeyValueConstructors(t *testing.T) {
+	tt := []struct {
+		name     string
+		actual   attribute.KeyValue
+		expected attribute.KeyValue
+	}{
+		{
+			name:   "Bool",
+			actual: attribute.Bool("k1", true),
+			expected: attribute.KeyValue{
+				Key:   "k1",
+				Value: attribute.BoolValue(true),
+			},
+		},
+		{
+			name:   "Int64",
+			actual: attribute.Int64("k1", 123),
+			expected: attribute.KeyValue{
+				Key:   "k1",
+				Value: attribute.Int64Value(123),
+			},
+		},
+		{
+			name:   "Float64",
+			actual: attribute.Float64("k1", 123.5),
+			expected: attribute.KeyValue{
+				Key:   "k1",
+				Value: attribute.Float64Value(123.5),
+			},
+		},
+		{
+			name:   "String",
+			actual: attribute.String("k1", "123.5"),
+			expected: attribute.KeyValue{
+				Key:   "k1",
+				Value: attribute.StringValue("123.5"),
+			},
+		},
+		{
+			name:   "Int",
+			actual: attribute.Int("k1", 123),
+			expected: attribute.KeyValue{
+				Key:   "k1",
+				Value: attribute.IntValue(123),
+			},
+		},
+	}
+
+	for _, test := range tt {
+		t.Run(test.name, func(t *testing.T) {
+			if diff := cmp.Diff(test.actual, test.expected, cmp.AllowUnexported(attribute.Value{})); diff != "" {
+				t.Fatal(diff)
+			}
+		})
+	}
+}
+
+func TestKeyValueValid(t *testing.T) {
+	tests := []struct {
+		desc  string
+		valid bool
+		kv    attribute.KeyValue
+	}{
+		{
+			desc:  "uninitialized KeyValue should be invalid",
+			valid: false,
+			kv:    attribute.KeyValue{},
+		},
+		{
+			desc:  "empty key value should be invalid",
+			valid: false,
+			kv:    attribute.Key("").Bool(true),
+		},
+		{
+			desc:  "INVALID value type should be invalid",
+			valid: false,
+			kv: attribute.KeyValue{
+				Key: attribute.Key("valid key"),
+				// Default type is INVALID.
+				Value: attribute.Value{},
+			},
+		},
+		{
+			desc:  "non-empty key with BOOL type Value should be valid",
+			valid: true,
+			kv:    attribute.Bool("bool", true),
+		},
+		{
+			desc:  "non-empty key with INT64 type Value should be valid",
+			valid: true,
+			kv:    attribute.Int64("int64", 0),
+		},
+		{
+			desc:  "non-empty key with FLOAT64 type Value should be valid",
+			valid: true,
+			kv:    attribute.Float64("float64", 0),
+		},
+		{
+			desc:  "non-empty key with STRING type Value should be valid",
+			valid: true,
+			kv:    attribute.String("string", ""),
+		},
+	}
+
+	for _, test := range tests {
+		if got, want := test.kv.Valid(), test.valid; got != want {
+			t.Error(test.desc)
+		}
+	}
+}
+
+func TestIncorrectCast(t *testing.T) {
+	testCases := []struct {
+		name string
+		val  attribute.Value
+	}{
+		{
+			name: "Float64",
+			val:  attribute.Float64Value(1.0),
+		},
+		{
+			name: "Int64",
+			val:  attribute.Int64Value(2),
+		},
+		{
+			name: "String",
+			val:  attribute.BoolValue(true),
+		},
+		{
+			name: "Float64Slice",
+			val:  attribute.Float64SliceValue([]float64{1.0}),
+		},
+		{
+			name: "Int64Slice",
+			val:  attribute.Int64SliceValue([]int64{2}),
+		},
+		{
+			name: "StringSlice",
+			val:  attribute.BoolSliceValue([]bool{true}),
+		},
+	}
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.NotPanics(t, func() {
+				tt.val.AsBool()
+				tt.val.AsBoolSlice()
+				tt.val.AsFloat64()
+				tt.val.AsFloat64Slice()
+				tt.val.AsInt64()
+				tt.val.AsInt64Slice()
+				tt.val.AsInterface()
+				tt.val.AsString()
+				tt.val.AsStringSlice()
+			})
+		})
+	}
+}

+ 429 - 0
pkg/go.opentelemetry.io/otel/attribute/set.go

@@ -0,0 +1,429 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute // import "go.opentelemetry.io/otel/attribute"
+
+import (
+	"encoding/json"
+	"reflect"
+	"sort"
+	"sync"
+)
+
+type (
+	// Set is the representation for a distinct attribute set. It manages an
+	// immutable set of attributes, with an internal cache for storing
+	// attribute encodings.
+	//
+	// This type supports the Equivalent method of comparison using values of
+	// type Distinct.
+	Set struct {
+		equivalent Distinct
+	}
+
+	// Distinct wraps a variable-size array of KeyValue, constructed with keys
+	// in sorted order. This can be used as a map key or for equality checking
+	// between Sets.
+	Distinct struct {
+		iface interface{}
+	}
+
+	// Sortable implements sort.Interface, used for sorting KeyValue. This is
+	// an exported type to support a memory optimization. A pointer to one of
+	// these is needed for the call to sort.Stable(), which the caller may
+	// provide in order to avoid an allocation. See NewSetWithSortable().
+	Sortable []KeyValue
+)
+
+var (
+	// keyValueType is used in computeDistinctReflect.
+	keyValueType = reflect.TypeOf(KeyValue{})
+
+	// emptySet is returned for empty attribute sets.
+	emptySet = &Set{
+		equivalent: Distinct{
+			iface: [0]KeyValue{},
+		},
+	}
+
+	// sortables is a pool of Sortables used to create Sets with a user does
+	// not provide one.
+	sortables = sync.Pool{
+		New: func() interface{} { return new(Sortable) },
+	}
+)
+
+// EmptySet returns a reference to a Set with no elements.
+//
+// This is a convenience provided for optimized calling utility.
+func EmptySet() *Set {
+	return emptySet
+}
+
+// reflectValue abbreviates reflect.ValueOf(d).
+func (d Distinct) reflectValue() reflect.Value {
+	return reflect.ValueOf(d.iface)
+}
+
+// Valid returns true if this value refers to a valid Set.
+func (d Distinct) Valid() bool {
+	return d.iface != nil
+}
+
+// Len returns the number of attributes in this set.
+func (l *Set) Len() int {
+	if l == nil || !l.equivalent.Valid() {
+		return 0
+	}
+	return l.equivalent.reflectValue().Len()
+}
+
+// Get returns the KeyValue at ordered position idx in this set.
+func (l *Set) Get(idx int) (KeyValue, bool) {
+	if l == nil || !l.equivalent.Valid() {
+		return KeyValue{}, false
+	}
+	value := l.equivalent.reflectValue()
+
+	if idx >= 0 && idx < value.Len() {
+		// Note: The Go compiler successfully avoids an allocation for
+		// the interface{} conversion here:
+		return value.Index(idx).Interface().(KeyValue), true
+	}
+
+	return KeyValue{}, false
+}
+
+// Value returns the value of a specified key in this set.
+func (l *Set) Value(k Key) (Value, bool) {
+	if l == nil || !l.equivalent.Valid() {
+		return Value{}, false
+	}
+	rValue := l.equivalent.reflectValue()
+	vlen := rValue.Len()
+
+	idx := sort.Search(vlen, func(idx int) bool {
+		return rValue.Index(idx).Interface().(KeyValue).Key >= k
+	})
+	if idx >= vlen {
+		return Value{}, false
+	}
+	keyValue := rValue.Index(idx).Interface().(KeyValue)
+	if k == keyValue.Key {
+		return keyValue.Value, true
+	}
+	return Value{}, false
+}
+
+// HasValue tests whether a key is defined in this set.
+func (l *Set) HasValue(k Key) bool {
+	if l == nil {
+		return false
+	}
+	_, ok := l.Value(k)
+	return ok
+}
+
+// Iter returns an iterator for visiting the attributes in this set.
+func (l *Set) Iter() Iterator {
+	return Iterator{
+		storage: l,
+		idx:     -1,
+	}
+}
+
+// ToSlice returns the set of attributes belonging to this set, sorted, where
+// keys appear no more than once.
+func (l *Set) ToSlice() []KeyValue {
+	iter := l.Iter()
+	return iter.ToSlice()
+}
+
+// Equivalent returns a value that may be used as a map key. The Distinct type
+// guarantees that the result will equal the equivalent. Distinct value of any
+// attribute set with the same elements as this, where sets are made unique by
+// choosing the last value in the input for any given key.
+func (l *Set) Equivalent() Distinct {
+	if l == nil || !l.equivalent.Valid() {
+		return emptySet.equivalent
+	}
+	return l.equivalent
+}
+
+// Equals returns true if the argument set is equivalent to this set.
+func (l *Set) Equals(o *Set) bool {
+	return l.Equivalent() == o.Equivalent()
+}
+
+// Encoded returns the encoded form of this set, according to encoder.
+func (l *Set) Encoded(encoder Encoder) string {
+	if l == nil || encoder == nil {
+		return ""
+	}
+
+	return encoder.Encode(l.Iter())
+}
+
+func empty() Set {
+	return Set{
+		equivalent: emptySet.equivalent,
+	}
+}
+
+// NewSet returns a new Set. See the documentation for
+// NewSetWithSortableFiltered for more details.
+//
+// Except for empty sets, this method adds an additional allocation compared
+// with calls that include a Sortable.
+func NewSet(kvs ...KeyValue) Set {
+	// Check for empty set.
+	if len(kvs) == 0 {
+		return empty()
+	}
+	srt := sortables.Get().(*Sortable)
+	s, _ := NewSetWithSortableFiltered(kvs, srt, nil)
+	sortables.Put(srt)
+	return s
+}
+
+// NewSetWithSortable returns a new Set. See the documentation for
+// NewSetWithSortableFiltered for more details.
+//
+// This call includes a Sortable option as a memory optimization.
+func NewSetWithSortable(kvs []KeyValue, tmp *Sortable) Set {
+	// Check for empty set.
+	if len(kvs) == 0 {
+		return empty()
+	}
+	s, _ := NewSetWithSortableFiltered(kvs, tmp, nil)
+	return s
+}
+
+// NewSetWithFiltered returns a new Set. See the documentation for
+// NewSetWithSortableFiltered for more details.
+//
+// This call includes a Filter to include/exclude attribute keys from the
+// return value. Excluded keys are returned as a slice of attribute values.
+func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
+	// Check for empty set.
+	if len(kvs) == 0 {
+		return empty(), nil
+	}
+	srt := sortables.Get().(*Sortable)
+	s, filtered := NewSetWithSortableFiltered(kvs, srt, filter)
+	sortables.Put(srt)
+	return s, filtered
+}
+
+// NewSetWithSortableFiltered returns a new Set.
+//
+// Duplicate keys are eliminated by taking the last value.  This
+// re-orders the input slice so that unique last-values are contiguous
+// at the end of the slice.
+//
+// This ensures the following:
+//
+// - Last-value-wins semantics
+// - Caller sees the reordering, but doesn't lose values
+// - Repeated call preserve last-value wins.
+//
+// Note that methods are defined on Set, although this returns Set. Callers
+// can avoid memory allocations by:
+//
+// - allocating a Sortable for use as a temporary in this method
+// - allocating a Set for storing the return value of this constructor.
+//
+// The result maintains a cache of encoded attributes, by attribute.EncoderID.
+// This value should not be copied after its first use.
+//
+// The second []KeyValue return value is a list of attributes that were
+// excluded by the Filter (if non-nil).
+func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (Set, []KeyValue) {
+	// Check for empty set.
+	if len(kvs) == 0 {
+		return empty(), nil
+	}
+
+	*tmp = kvs
+
+	// Stable sort so the following de-duplication can implement
+	// last-value-wins semantics.
+	sort.Stable(tmp)
+
+	*tmp = nil
+
+	position := len(kvs) - 1
+	offset := position - 1
+
+	// The requirements stated above require that the stable
+	// result be placed in the end of the input slice, while
+	// overwritten values are swapped to the beginning.
+	//
+	// De-duplicate with last-value-wins semantics.  Preserve
+	// duplicate values at the beginning of the input slice.
+	for ; offset >= 0; offset-- {
+		if kvs[offset].Key == kvs[position].Key {
+			continue
+		}
+		position--
+		kvs[offset], kvs[position] = kvs[position], kvs[offset]
+	}
+	if filter != nil {
+		return filterSet(kvs[position:], filter)
+	}
+	return Set{
+		equivalent: computeDistinct(kvs[position:]),
+	}, nil
+}
+
+// filterSet reorders kvs so that included keys are contiguous at the end of
+// the slice, while excluded keys precede the included keys.
+func filterSet(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
+	var excluded []KeyValue
+
+	// Move attributes that do not match the filter so they're adjacent before
+	// calling computeDistinct().
+	distinctPosition := len(kvs)
+
+	// Swap indistinct keys forward and distinct keys toward the
+	// end of the slice.
+	offset := len(kvs) - 1
+	for ; offset >= 0; offset-- {
+		if filter(kvs[offset]) {
+			distinctPosition--
+			kvs[offset], kvs[distinctPosition] = kvs[distinctPosition], kvs[offset]
+			continue
+		}
+	}
+	excluded = kvs[:distinctPosition]
+
+	return Set{
+		equivalent: computeDistinct(kvs[distinctPosition:]),
+	}, excluded
+}
+
+// Filter returns a filtered copy of this Set. See the documentation for
+// NewSetWithSortableFiltered for more details.
+func (l *Set) Filter(re Filter) (Set, []KeyValue) {
+	if re == nil {
+		return Set{
+			equivalent: l.equivalent,
+		}, nil
+	}
+
+	// Note: This could be refactored to avoid the temporary slice
+	// allocation, if it proves to be expensive.
+	return filterSet(l.ToSlice(), re)
+}
+
+// computeDistinct returns a Distinct using either the fixed- or
+// reflect-oriented code path, depending on the size of the input. The input
+// slice is assumed to already be sorted and de-duplicated.
+func computeDistinct(kvs []KeyValue) Distinct {
+	iface := computeDistinctFixed(kvs)
+	if iface == nil {
+		iface = computeDistinctReflect(kvs)
+	}
+	return Distinct{
+		iface: iface,
+	}
+}
+
+// computeDistinctFixed computes a Distinct for small slices. It returns nil
+// if the input is too large for this code path.
+func computeDistinctFixed(kvs []KeyValue) interface{} {
+	switch len(kvs) {
+	case 1:
+		ptr := new([1]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 2:
+		ptr := new([2]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 3:
+		ptr := new([3]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 4:
+		ptr := new([4]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 5:
+		ptr := new([5]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 6:
+		ptr := new([6]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 7:
+		ptr := new([7]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 8:
+		ptr := new([8]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 9:
+		ptr := new([9]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	case 10:
+		ptr := new([10]KeyValue)
+		copy((*ptr)[:], kvs)
+		return *ptr
+	default:
+		return nil
+	}
+}
+
+// computeDistinctReflect computes a Distinct using reflection, works for any
+// size input.
+func computeDistinctReflect(kvs []KeyValue) interface{} {
+	at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem()
+	for i, keyValue := range kvs {
+		*(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue
+	}
+	return at.Interface()
+}
+
+// MarshalJSON returns the JSON encoding of the Set.
+func (l *Set) MarshalJSON() ([]byte, error) {
+	return json.Marshal(l.equivalent.iface)
+}
+
+// MarshalLog is the marshaling function used by the logging system to represent this exporter.
+func (l Set) MarshalLog() interface{} {
+	kvs := make(map[string]string)
+	for _, kv := range l.ToSlice() {
+		kvs[string(kv.Key)] = kv.Value.Emit()
+	}
+	return kvs
+}
+
+// Len implements sort.Interface.
+func (l *Sortable) Len() int {
+	return len(*l)
+}
+
+// Swap implements sort.Interface.
+func (l *Sortable) Swap(i, j int) {
+	(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
+}
+
+// Less implements sort.Interface.
+func (l *Sortable) Less(i, j int) bool {
+	return (*l)[i].Key < (*l)[j].Key
+}

+ 227 - 0
pkg/go.opentelemetry.io/otel/attribute/set_test.go

@@ -0,0 +1,227 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute_test
+
+import (
+	"reflect"
+	"regexp"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+type testCase struct {
+	kvs []attribute.KeyValue
+
+	keyRe *regexp.Regexp
+
+	encoding string
+	fullEnc  string
+}
+
+func expect(enc string, kvs ...attribute.KeyValue) testCase {
+	return testCase{
+		kvs:      kvs,
+		encoding: enc,
+	}
+}
+
+func expectFiltered(enc, filter, fullEnc string, kvs ...attribute.KeyValue) testCase {
+	return testCase{
+		kvs:      kvs,
+		keyRe:    regexp.MustCompile(filter),
+		encoding: enc,
+		fullEnc:  fullEnc,
+	}
+}
+
+func TestSetDedup(t *testing.T) {
+	cases := []testCase{
+		expect("A=B", attribute.String("A", "2"), attribute.String("A", "B")),
+		expect("A=B", attribute.String("A", "2"), attribute.Int("A", 1), attribute.String("A", "B")),
+		expect("A=B", attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
+
+		expect("A=B,C=D", attribute.String("A", "1"), attribute.String("C", "D"), attribute.String("A", "B")),
+		expect("A=B,C=D", attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
+		expect("A=B,C=D", attribute.Float64("C", 1.2), attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
+		expect("A=B,C=D", attribute.String("C", "D"), attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
+		expect("A=B,C=D", attribute.String("A", "B"), attribute.String("C", "D"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
+		expect("A=B,C=D", attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B"), attribute.String("C", "D")),
+	}
+	enc := attribute.DefaultEncoder()
+
+	s2d := map[string][]attribute.Distinct{}
+	d2s := map[attribute.Distinct][]string{}
+
+	for _, tc := range cases {
+		cpy := make([]attribute.KeyValue, len(tc.kvs))
+		copy(cpy, tc.kvs)
+		sl := attribute.NewSet(cpy...)
+
+		// Ensure that the input was reordered but no elements went missing.
+		require.ElementsMatch(t, tc.kvs, cpy)
+
+		str := sl.Encoded(enc)
+		equ := sl.Equivalent()
+
+		s2d[str] = append(s2d[str], equ)
+		d2s[equ] = append(d2s[equ], str)
+
+		require.Equal(t, tc.encoding, str)
+	}
+
+	for s, d := range s2d {
+		// No other Distinct values are equal to this.
+		for s2, d2 := range s2d {
+			if s2 == s {
+				continue
+			}
+			for _, elt := range d {
+				for _, otherDistinct := range d2 {
+					require.NotEqual(t, otherDistinct, elt)
+				}
+			}
+		}
+		for _, strings := range d2s {
+			if strings[0] == s {
+				continue
+			}
+			for _, otherString := range strings {
+				require.NotEqual(t, otherString, s)
+			}
+		}
+	}
+
+	for d, s := range d2s {
+		// No other Distinct values are equal to this.
+		for d2, s2 := range d2s {
+			if d2 == d {
+				continue
+			}
+			for _, elt := range s {
+				for _, otherDistinct := range s2 {
+					require.NotEqual(t, otherDistinct, elt)
+				}
+			}
+		}
+		for _, distincts := range s2d {
+			if distincts[0] == d {
+				continue
+			}
+			for _, otherDistinct := range distincts {
+				require.NotEqual(t, otherDistinct, d)
+			}
+		}
+	}
+}
+
+func TestUniqueness(t *testing.T) {
+	short := []attribute.KeyValue{
+		attribute.String("A", "0"),
+		attribute.String("B", "2"),
+		attribute.String("A", "1"),
+	}
+	long := []attribute.KeyValue{
+		attribute.String("B", "2"),
+		attribute.String("C", "5"),
+		attribute.String("B", "2"),
+		attribute.String("C", "1"),
+		attribute.String("A", "4"),
+		attribute.String("C", "3"),
+		attribute.String("A", "1"),
+	}
+	cases := []testCase{
+		expectFiltered("A=1", "^A$", "B=2", short...),
+		expectFiltered("B=2", "^B$", "A=1", short...),
+		expectFiltered("A=1,B=2", "^A|B$", "", short...),
+		expectFiltered("", "^C", "A=1,B=2", short...),
+
+		expectFiltered("A=1,C=3", "A|C", "B=2", long...),
+		expectFiltered("B=2,C=3", "C|B", "A=1", long...),
+		expectFiltered("C=3", "C", "A=1,B=2", long...),
+		expectFiltered("", "D", "A=1,B=2,C=3", long...),
+	}
+	enc := attribute.DefaultEncoder()
+
+	for _, tc := range cases {
+		cpy := make([]attribute.KeyValue, len(tc.kvs))
+		copy(cpy, tc.kvs)
+		distinct, uniq := attribute.NewSetWithFiltered(cpy, func(attr attribute.KeyValue) bool {
+			return tc.keyRe.MatchString(string(attr.Key))
+		})
+
+		full := attribute.NewSet(uniq...)
+
+		require.Equal(t, tc.encoding, distinct.Encoded(enc))
+		require.Equal(t, tc.fullEnc, full.Encoded(enc))
+	}
+}
+
+func TestLookup(t *testing.T) {
+	set := attribute.NewSet(attribute.Int("C", 3), attribute.Int("A", 1), attribute.Int("B", 2))
+
+	value, has := set.Value("C")
+	require.True(t, has)
+	require.Equal(t, int64(3), value.AsInt64())
+
+	value, has = set.Value("B")
+	require.True(t, has)
+	require.Equal(t, int64(2), value.AsInt64())
+
+	value, has = set.Value("A")
+	require.True(t, has)
+	require.Equal(t, int64(1), value.AsInt64())
+
+	_, has = set.Value("D")
+	require.False(t, has)
+}
+
+func TestZeroSetExportedMethodsNoPanic(t *testing.T) {
+	rType := reflect.TypeOf((*attribute.Set)(nil))
+	rVal := reflect.ValueOf(&attribute.Set{})
+	for n := 0; n < rType.NumMethod(); n++ {
+		mType := rType.Method(n)
+		if !mType.IsExported() {
+			t.Logf("ignoring unexported %s", mType.Name)
+			continue
+		}
+		t.Run(mType.Name, func(t *testing.T) {
+			m := rVal.MethodByName(mType.Name)
+			if !m.IsValid() {
+				t.Errorf("unknown method: %s", mType.Name)
+			}
+			assert.NotPanics(t, func() { _ = m.Call(args(mType)) })
+		})
+	}
+}
+
+func args(m reflect.Method) []reflect.Value {
+	numIn := m.Type.NumIn() - 1 // Do not include the receiver arg.
+	if numIn <= 0 {
+		return nil
+	}
+	if m.Type.IsVariadic() {
+		numIn--
+	}
+	out := make([]reflect.Value, numIn)
+	for i := range out {
+		aType := m.Type.In(i + 1) // Skip receiver arg.
+		out[i] = reflect.New(aType).Elem()
+	}
+	return out
+}

+ 31 - 0
pkg/go.opentelemetry.io/otel/attribute/type_string.go

@@ -0,0 +1,31 @@
+// Code generated by "stringer -type=Type"; DO NOT EDIT.
+
+package attribute
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[INVALID-0]
+	_ = x[BOOL-1]
+	_ = x[INT64-2]
+	_ = x[FLOAT64-3]
+	_ = x[STRING-4]
+	_ = x[BOOLSLICE-5]
+	_ = x[INT64SLICE-6]
+	_ = x[FLOAT64SLICE-7]
+	_ = x[STRINGSLICE-8]
+}
+
+const _Type_name = "INVALIDBOOLINT64FLOAT64STRINGBOOLSLICEINT64SLICEFLOAT64SLICESTRINGSLICE"
+
+var _Type_index = [...]uint8{0, 7, 11, 16, 23, 29, 38, 48, 60, 71}
+
+func (i Type) String() string {
+	if i < 0 || i >= Type(len(_Type_index)-1) {
+		return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _Type_name[_Type_index[i]:_Type_index[i+1]]
+}

+ 270 - 0
pkg/go.opentelemetry.io/otel/attribute/value.go

@@ -0,0 +1,270 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute // import "go.opentelemetry.io/otel/attribute"
+
+import (
+	"encoding/json"
+	"fmt"
+	"reflect"
+	"strconv"
+
+	"go.opentelemetry.io/otel/internal"
+	"go.opentelemetry.io/otel/internal/attribute"
+)
+
+//go:generate stringer -type=Type
+
+// Type describes the type of the data Value holds.
+type Type int // nolint: revive  // redefines builtin Type.
+
+// Value represents the value part in key-value pairs.
+type Value struct {
+	vtype    Type
+	numeric  uint64
+	stringly string
+	slice    interface{}
+}
+
+const (
+	// INVALID is used for a Value with no value set.
+	INVALID Type = iota
+	// BOOL is a boolean Type Value.
+	BOOL
+	// INT64 is a 64-bit signed integral Type Value.
+	INT64
+	// FLOAT64 is a 64-bit floating point Type Value.
+	FLOAT64
+	// STRING is a string Type Value.
+	STRING
+	// BOOLSLICE is a slice of booleans Type Value.
+	BOOLSLICE
+	// INT64SLICE is a slice of 64-bit signed integral numbers Type Value.
+	INT64SLICE
+	// FLOAT64SLICE is a slice of 64-bit floating point numbers Type Value.
+	FLOAT64SLICE
+	// STRINGSLICE is a slice of strings Type Value.
+	STRINGSLICE
+)
+
+// BoolValue creates a BOOL Value.
+func BoolValue(v bool) Value {
+	return Value{
+		vtype:   BOOL,
+		numeric: internal.BoolToRaw(v),
+	}
+}
+
+// BoolSliceValue creates a BOOLSLICE Value.
+func BoolSliceValue(v []bool) Value {
+	return Value{vtype: BOOLSLICE, slice: attribute.BoolSliceValue(v)}
+}
+
+// IntValue creates an INT64 Value.
+func IntValue(v int) Value {
+	return Int64Value(int64(v))
+}
+
+// IntSliceValue creates an INTSLICE Value.
+func IntSliceValue(v []int) Value {
+	var int64Val int64
+	cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(int64Val)))
+	for i, val := range v {
+		cp.Elem().Index(i).SetInt(int64(val))
+	}
+	return Value{
+		vtype: INT64SLICE,
+		slice: cp.Elem().Interface(),
+	}
+}
+
+// Int64Value creates an INT64 Value.
+func Int64Value(v int64) Value {
+	return Value{
+		vtype:   INT64,
+		numeric: internal.Int64ToRaw(v),
+	}
+}
+
+// Int64SliceValue creates an INT64SLICE Value.
+func Int64SliceValue(v []int64) Value {
+	return Value{vtype: INT64SLICE, slice: attribute.Int64SliceValue(v)}
+}
+
+// Float64Value creates a FLOAT64 Value.
+func Float64Value(v float64) Value {
+	return Value{
+		vtype:   FLOAT64,
+		numeric: internal.Float64ToRaw(v),
+	}
+}
+
+// Float64SliceValue creates a FLOAT64SLICE Value.
+func Float64SliceValue(v []float64) Value {
+	return Value{vtype: FLOAT64SLICE, slice: attribute.Float64SliceValue(v)}
+}
+
+// StringValue creates a STRING Value.
+func StringValue(v string) Value {
+	return Value{
+		vtype:    STRING,
+		stringly: v,
+	}
+}
+
+// StringSliceValue creates a STRINGSLICE Value.
+func StringSliceValue(v []string) Value {
+	return Value{vtype: STRINGSLICE, slice: attribute.StringSliceValue(v)}
+}
+
+// Type returns a type of the Value.
+func (v Value) Type() Type {
+	return v.vtype
+}
+
+// AsBool returns the bool value. Make sure that the Value's type is
+// BOOL.
+func (v Value) AsBool() bool {
+	return internal.RawToBool(v.numeric)
+}
+
+// AsBoolSlice returns the []bool value. Make sure that the Value's type is
+// BOOLSLICE.
+func (v Value) AsBoolSlice() []bool {
+	if v.vtype != BOOLSLICE {
+		return nil
+	}
+	return v.asBoolSlice()
+}
+
+func (v Value) asBoolSlice() []bool {
+	return attribute.AsBoolSlice(v.slice)
+}
+
+// AsInt64 returns the int64 value. Make sure that the Value's type is
+// INT64.
+func (v Value) AsInt64() int64 {
+	return internal.RawToInt64(v.numeric)
+}
+
+// AsInt64Slice returns the []int64 value. Make sure that the Value's type is
+// INT64SLICE.
+func (v Value) AsInt64Slice() []int64 {
+	if v.vtype != INT64SLICE {
+		return nil
+	}
+	return v.asInt64Slice()
+}
+
+func (v Value) asInt64Slice() []int64 {
+	return attribute.AsInt64Slice(v.slice)
+}
+
+// AsFloat64 returns the float64 value. Make sure that the Value's
+// type is FLOAT64.
+func (v Value) AsFloat64() float64 {
+	return internal.RawToFloat64(v.numeric)
+}
+
+// AsFloat64Slice returns the []float64 value. Make sure that the Value's type is
+// FLOAT64SLICE.
+func (v Value) AsFloat64Slice() []float64 {
+	if v.vtype != FLOAT64SLICE {
+		return nil
+	}
+	return v.asFloat64Slice()
+}
+
+func (v Value) asFloat64Slice() []float64 {
+	return attribute.AsFloat64Slice(v.slice)
+}
+
+// AsString returns the string value. Make sure that the Value's type
+// is STRING.
+func (v Value) AsString() string {
+	return v.stringly
+}
+
+// AsStringSlice returns the []string value. Make sure that the Value's type is
+// STRINGSLICE.
+func (v Value) AsStringSlice() []string {
+	if v.vtype != STRINGSLICE {
+		return nil
+	}
+	return v.asStringSlice()
+}
+
+func (v Value) asStringSlice() []string {
+	return attribute.AsStringSlice(v.slice)
+}
+
+type unknownValueType struct{}
+
+// AsInterface returns Value's data as interface{}.
+func (v Value) AsInterface() interface{} {
+	switch v.Type() {
+	case BOOL:
+		return v.AsBool()
+	case BOOLSLICE:
+		return v.asBoolSlice()
+	case INT64:
+		return v.AsInt64()
+	case INT64SLICE:
+		return v.asInt64Slice()
+	case FLOAT64:
+		return v.AsFloat64()
+	case FLOAT64SLICE:
+		return v.asFloat64Slice()
+	case STRING:
+		return v.stringly
+	case STRINGSLICE:
+		return v.asStringSlice()
+	}
+	return unknownValueType{}
+}
+
+// Emit returns a string representation of Value's data.
+func (v Value) Emit() string {
+	switch v.Type() {
+	case BOOLSLICE:
+		return fmt.Sprint(v.asBoolSlice())
+	case BOOL:
+		return strconv.FormatBool(v.AsBool())
+	case INT64SLICE:
+		return fmt.Sprint(v.asInt64Slice())
+	case INT64:
+		return strconv.FormatInt(v.AsInt64(), 10)
+	case FLOAT64SLICE:
+		return fmt.Sprint(v.asFloat64Slice())
+	case FLOAT64:
+		return fmt.Sprint(v.AsFloat64())
+	case STRINGSLICE:
+		return fmt.Sprint(v.asStringSlice())
+	case STRING:
+		return v.stringly
+	default:
+		return "unknown"
+	}
+}
+
+// MarshalJSON returns the JSON encoding of the Value.
+func (v Value) MarshalJSON() ([]byte, error) {
+	var jsonVal struct {
+		Type  string
+		Value interface{}
+	}
+	jsonVal.Type = v.Type().String()
+	jsonVal.Value = v.AsInterface()
+	return json.Marshal(jsonVal)
+}

+ 186 - 0
pkg/go.opentelemetry.io/otel/attribute/value_test.go

@@ -0,0 +1,186 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package attribute_test
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/stretchr/testify/assert"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+func TestValue(t *testing.T) {
+	k := attribute.Key("test")
+	for _, testcase := range []struct {
+		name      string
+		value     attribute.Value
+		wantType  attribute.Type
+		wantValue interface{}
+	}{
+		{
+			name:      "Key.Bool() correctly returns keys's internal bool value",
+			value:     k.Bool(true).Value,
+			wantType:  attribute.BOOL,
+			wantValue: true,
+		},
+		{
+			name:      "Key.BoolSlice() correctly returns keys's internal []bool value",
+			value:     k.BoolSlice([]bool{true, false, true}).Value,
+			wantType:  attribute.BOOLSLICE,
+			wantValue: []bool{true, false, true},
+		},
+		{
+			name:      "Key.Int64() correctly returns keys's internal int64 value",
+			value:     k.Int64(42).Value,
+			wantType:  attribute.INT64,
+			wantValue: int64(42),
+		},
+		{
+			name:      "Key.Int64Slice() correctly returns keys's internal []int64 value",
+			value:     k.Int64Slice([]int64{42, -3, 12}).Value,
+			wantType:  attribute.INT64SLICE,
+			wantValue: []int64{42, -3, 12},
+		},
+		{
+			name:      "Key.Int() correctly returns keys's internal signed integral value",
+			value:     k.Int(42).Value,
+			wantType:  attribute.INT64,
+			wantValue: int64(42),
+		},
+		{
+			name:      "Key.IntSlice() correctly returns keys's internal []int64 value",
+			value:     k.IntSlice([]int{42, -3, 12}).Value,
+			wantType:  attribute.INT64SLICE,
+			wantValue: []int64{42, -3, 12},
+		},
+		{
+			name:      "Key.Float64() correctly returns keys's internal float64 value",
+			value:     k.Float64(42.1).Value,
+			wantType:  attribute.FLOAT64,
+			wantValue: 42.1,
+		},
+		{
+			name:      "Key.Float64Slice() correctly returns keys's internal []float64 value",
+			value:     k.Float64Slice([]float64{42, -3, 12}).Value,
+			wantType:  attribute.FLOAT64SLICE,
+			wantValue: []float64{42, -3, 12},
+		},
+		{
+			name:      "Key.String() correctly returns keys's internal string value",
+			value:     k.String("foo").Value,
+			wantType:  attribute.STRING,
+			wantValue: "foo",
+		},
+		{
+			name:      "Key.StringSlice() correctly returns keys's internal []string value",
+			value:     k.StringSlice([]string{"forty-two", "negative three", "twelve"}).Value,
+			wantType:  attribute.STRINGSLICE,
+			wantValue: []string{"forty-two", "negative three", "twelve"},
+		},
+	} {
+		t.Logf("Running test case %s", testcase.name)
+		if testcase.value.Type() != testcase.wantType {
+			t.Errorf("wrong value type, got %#v, expected %#v", testcase.value.Type(), testcase.wantType)
+		}
+		if testcase.wantType == attribute.INVALID {
+			continue
+		}
+		got := testcase.value.AsInterface()
+		if diff := cmp.Diff(testcase.wantValue, got); diff != "" {
+			t.Errorf("+got, -want: %s", diff)
+		}
+	}
+}
+
+func TestSetComparability(t *testing.T) {
+	pairs := [][2]attribute.KeyValue{
+		{
+			attribute.Bool("Bool", true),
+			attribute.Bool("Bool", true),
+		},
+		{
+			attribute.BoolSlice("BoolSlice", []bool{true, false, true}),
+			attribute.BoolSlice("BoolSlice", []bool{true, false, true}),
+		},
+		{
+			attribute.Int("Int", 34),
+			attribute.Int("Int", 34),
+		},
+		{
+			attribute.IntSlice("IntSlice", []int{312, 1, -2}),
+			attribute.IntSlice("IntSlice", []int{312, 1, -2}),
+		},
+		{
+			attribute.Int64("Int64", 98),
+			attribute.Int64("Int64", 98),
+		},
+		{
+			attribute.Int64Slice("Int64Slice", []int64{12, 1298, -219, 2}),
+			attribute.Int64Slice("Int64Slice", []int64{12, 1298, -219, 2}),
+		},
+		{
+			attribute.Float64("Float64", 19.09),
+			attribute.Float64("Float64", 19.09),
+		},
+		{
+			attribute.Float64Slice("Float64Slice", []float64{12398.1, -37.1713873737, 3}),
+			attribute.Float64Slice("Float64Slice", []float64{12398.1, -37.1713873737, 3}),
+		},
+		{
+			attribute.String("String", "string value"),
+			attribute.String("String", "string value"),
+		},
+		{
+			attribute.StringSlice("StringSlice", []string{"one", "two", "three"}),
+			attribute.StringSlice("StringSlice", []string{"one", "two", "three"}),
+		},
+	}
+
+	for _, p := range pairs {
+		s0, s1 := attribute.NewSet(p[0]), attribute.NewSet(p[1])
+		m := map[attribute.Set]struct{}{s0: {}}
+		_, ok := m[s1]
+		assert.Truef(t, ok, "%s not comparable", p[0].Value.Type())
+	}
+}
+
+func TestAsSlice(t *testing.T) {
+	bs1 := []bool{true, false, true}
+	kv := attribute.BoolSlice("BoolSlice", bs1)
+	bs2 := kv.Value.AsBoolSlice()
+	assert.Equal(t, bs1, bs2)
+
+	i64s1 := []int64{12, 1298, -219, 2}
+	kv = attribute.Int64Slice("Int64Slice", i64s1)
+	i64s2 := kv.Value.AsInt64Slice()
+	assert.Equal(t, i64s1, i64s2)
+
+	is1 := []int{12, 1298, -219, 2}
+	kv = attribute.IntSlice("IntSlice", is1)
+	i64s2 = kv.Value.AsInt64Slice()
+	assert.Equal(t, i64s1, i64s2)
+
+	fs1 := []float64{12398.1, -37.1713873737, 3}
+	kv = attribute.Float64Slice("Float64Slice", fs1)
+	fs2 := kv.Value.AsFloat64Slice()
+	assert.Equal(t, fs1, fs2)
+
+	ss1 := []string{"one", "two", "three"}
+	kv = attribute.StringSlice("StringSlice", ss1)
+	ss2 := kv.Value.AsStringSlice()
+	assert.Equal(t, ss1, ss2)
+}

+ 552 - 0
pkg/go.opentelemetry.io/otel/baggage/baggage.go

@@ -0,0 +1,552 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package baggage // import "go.opentelemetry.io/otel/baggage"
+
+import (
+	"errors"
+	"fmt"
+	"net/url"
+	"regexp"
+	"strings"
+
+	"go.opentelemetry.io/otel/internal/baggage"
+)
+
+const (
+	maxMembers               = 180
+	maxBytesPerMembers       = 4096
+	maxBytesPerBaggageString = 8192
+
+	listDelimiter     = ","
+	keyValueDelimiter = "="
+	propertyDelimiter = ";"
+
+	keyDef      = `([\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5a\x5e-\x7a\x7c\x7e]+)`
+	valueDef    = `([\x21\x23-\x2b\x2d-\x3a\x3c-\x5B\x5D-\x7e]*)`
+	keyValueDef = `\s*` + keyDef + `\s*` + keyValueDelimiter + `\s*` + valueDef + `\s*`
+)
+
+var (
+	keyRe      = regexp.MustCompile(`^` + keyDef + `$`)
+	valueRe    = regexp.MustCompile(`^` + valueDef + `$`)
+	propertyRe = regexp.MustCompile(`^(?:\s*` + keyDef + `\s*|` + keyValueDef + `)$`)
+)
+
+var (
+	errInvalidKey      = errors.New("invalid key")
+	errInvalidValue    = errors.New("invalid value")
+	errInvalidProperty = errors.New("invalid baggage list-member property")
+	errInvalidMember   = errors.New("invalid baggage list-member")
+	errMemberNumber    = errors.New("too many list-members in baggage-string")
+	errMemberBytes     = errors.New("list-member too large")
+	errBaggageBytes    = errors.New("baggage-string too large")
+)
+
+// Property is an additional metadata entry for a baggage list-member.
+type Property struct {
+	key, value string
+
+	// hasValue indicates if a zero-value value means the property does not
+	// have a value or if it was the zero-value.
+	hasValue bool
+}
+
+// NewKeyProperty returns a new Property for key.
+//
+// If key is invalid, an error will be returned.
+func NewKeyProperty(key string) (Property, error) {
+	if !keyRe.MatchString(key) {
+		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key)
+	}
+
+	p := Property{key: key}
+	return p, nil
+}
+
+// NewKeyValueProperty returns a new Property for key with value.
+//
+// If key or value are invalid, an error will be returned.
+func NewKeyValueProperty(key, value string) (Property, error) {
+	if !keyRe.MatchString(key) {
+		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key)
+	}
+	if !valueRe.MatchString(value) {
+		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, value)
+	}
+
+	p := Property{
+		key:      key,
+		value:    value,
+		hasValue: true,
+	}
+	return p, nil
+}
+
+func newInvalidProperty() Property {
+	return Property{}
+}
+
+// parseProperty attempts to decode a Property from the passed string. It
+// returns an error if the input is invalid according to the W3C Baggage
+// specification.
+func parseProperty(property string) (Property, error) {
+	if property == "" {
+		return newInvalidProperty(), nil
+	}
+
+	match := propertyRe.FindStringSubmatch(property)
+	if len(match) != 4 {
+		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidProperty, property)
+	}
+
+	var p Property
+	if match[1] != "" {
+		p.key = match[1]
+	} else {
+		p.key = match[2]
+		p.value = match[3]
+		p.hasValue = true
+	}
+
+	return p, nil
+}
+
+// validate ensures p conforms to the W3C Baggage specification, returning an
+// error otherwise.
+func (p Property) validate() error {
+	errFunc := func(err error) error {
+		return fmt.Errorf("invalid property: %w", err)
+	}
+
+	if !keyRe.MatchString(p.key) {
+		return errFunc(fmt.Errorf("%w: %q", errInvalidKey, p.key))
+	}
+	if p.hasValue && !valueRe.MatchString(p.value) {
+		return errFunc(fmt.Errorf("%w: %q", errInvalidValue, p.value))
+	}
+	if !p.hasValue && p.value != "" {
+		return errFunc(errors.New("inconsistent value"))
+	}
+	return nil
+}
+
+// Key returns the Property key.
+func (p Property) Key() string {
+	return p.key
+}
+
+// Value returns the Property value. Additionally, a boolean value is returned
+// indicating if the returned value is the empty if the Property has a value
+// that is empty or if the value is not set.
+func (p Property) Value() (string, bool) {
+	return p.value, p.hasValue
+}
+
+// String encodes Property into a string compliant with the W3C Baggage
+// specification.
+func (p Property) String() string {
+	if p.hasValue {
+		return fmt.Sprintf("%s%s%v", p.key, keyValueDelimiter, p.value)
+	}
+	return p.key
+}
+
+type properties []Property
+
+func fromInternalProperties(iProps []baggage.Property) properties {
+	if len(iProps) == 0 {
+		return nil
+	}
+
+	props := make(properties, len(iProps))
+	for i, p := range iProps {
+		props[i] = Property{
+			key:      p.Key,
+			value:    p.Value,
+			hasValue: p.HasValue,
+		}
+	}
+	return props
+}
+
+func (p properties) asInternal() []baggage.Property {
+	if len(p) == 0 {
+		return nil
+	}
+
+	iProps := make([]baggage.Property, len(p))
+	for i, prop := range p {
+		iProps[i] = baggage.Property{
+			Key:      prop.key,
+			Value:    prop.value,
+			HasValue: prop.hasValue,
+		}
+	}
+	return iProps
+}
+
+func (p properties) Copy() properties {
+	if len(p) == 0 {
+		return nil
+	}
+
+	props := make(properties, len(p))
+	copy(props, p)
+	return props
+}
+
+// validate ensures each Property in p conforms to the W3C Baggage
+// specification, returning an error otherwise.
+func (p properties) validate() error {
+	for _, prop := range p {
+		if err := prop.validate(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// String encodes properties into a string compliant with the W3C Baggage
+// specification.
+func (p properties) String() string {
+	props := make([]string, len(p))
+	for i, prop := range p {
+		props[i] = prop.String()
+	}
+	return strings.Join(props, propertyDelimiter)
+}
+
+// Member is a list-member of a baggage-string as defined by the W3C Baggage
+// specification.
+type Member struct {
+	key, value string
+	properties properties
+
+	// hasData indicates whether the created property contains data or not.
+	// Properties that do not contain data are invalid with no other check
+	// required.
+	hasData bool
+}
+
+// NewMember returns a new Member from the passed arguments. The key will be
+// used directly while the value will be url decoded after validation. An error
+// is returned if the created Member would be invalid according to the W3C
+// Baggage specification.
+func NewMember(key, value string, props ...Property) (Member, error) {
+	m := Member{
+		key:        key,
+		value:      value,
+		properties: properties(props).Copy(),
+		hasData:    true,
+	}
+	if err := m.validate(); err != nil {
+		return newInvalidMember(), err
+	}
+	decodedValue, err := url.QueryUnescape(value)
+	if err != nil {
+		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
+	}
+	m.value = decodedValue
+	return m, nil
+}
+
+func newInvalidMember() Member {
+	return Member{}
+}
+
+// parseMember attempts to decode a Member from the passed string. It returns
+// an error if the input is invalid according to the W3C Baggage
+// specification.
+func parseMember(member string) (Member, error) {
+	if n := len(member); n > maxBytesPerMembers {
+		return newInvalidMember(), fmt.Errorf("%w: %d", errMemberBytes, n)
+	}
+
+	var (
+		key, value string
+		props      properties
+	)
+
+	keyValue, properties, found := strings.Cut(member, propertyDelimiter)
+	if found {
+		// Parse the member properties.
+		for _, pStr := range strings.Split(properties, propertyDelimiter) {
+			p, err := parseProperty(pStr)
+			if err != nil {
+				return newInvalidMember(), err
+			}
+			props = append(props, p)
+		}
+	}
+	// Parse the member key/value pair.
+
+	// Take into account a value can contain equal signs (=).
+	k, v, found := strings.Cut(keyValue, keyValueDelimiter)
+	if !found {
+		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, member)
+	}
+	// "Leading and trailing whitespaces are allowed but MUST be trimmed
+	// when converting the header into a data structure."
+	key = strings.TrimSpace(k)
+	var err error
+	value, err = url.QueryUnescape(strings.TrimSpace(v))
+	if err != nil {
+		return newInvalidMember(), fmt.Errorf("%w: %q", err, value)
+	}
+	if !keyRe.MatchString(key) {
+		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, key)
+	}
+	if !valueRe.MatchString(value) {
+		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
+	}
+
+	return Member{key: key, value: value, properties: props, hasData: true}, nil
+}
+
+// validate ensures m conforms to the W3C Baggage specification.
+// A key is just an ASCII string, but a value must be URL encoded UTF-8,
+// returning an error otherwise.
+func (m Member) validate() error {
+	if !m.hasData {
+		return fmt.Errorf("%w: %q", errInvalidMember, m)
+	}
+
+	if !keyRe.MatchString(m.key) {
+		return fmt.Errorf("%w: %q", errInvalidKey, m.key)
+	}
+	if !valueRe.MatchString(m.value) {
+		return fmt.Errorf("%w: %q", errInvalidValue, m.value)
+	}
+	return m.properties.validate()
+}
+
+// Key returns the Member key.
+func (m Member) Key() string { return m.key }
+
+// Value returns the Member value.
+func (m Member) Value() string { return m.value }
+
+// Properties returns a copy of the Member properties.
+func (m Member) Properties() []Property { return m.properties.Copy() }
+
+// String encodes Member into a string compliant with the W3C Baggage
+// specification.
+func (m Member) String() string {
+	// A key is just an ASCII string, but a value is URL encoded UTF-8.
+	s := fmt.Sprintf("%s%s%s", m.key, keyValueDelimiter, url.QueryEscape(m.value))
+	if len(m.properties) > 0 {
+		s = fmt.Sprintf("%s%s%s", s, propertyDelimiter, m.properties.String())
+	}
+	return s
+}
+
+// Baggage is a list of baggage members representing the baggage-string as
+// defined by the W3C Baggage specification.
+type Baggage struct { //nolint:golint
+	list baggage.List
+}
+
+// New returns a new valid Baggage. It returns an error if it results in a
+// Baggage exceeding limits set in that specification.
+//
+// It expects all the provided members to have already been validated.
+func New(members ...Member) (Baggage, error) {
+	if len(members) == 0 {
+		return Baggage{}, nil
+	}
+
+	b := make(baggage.List)
+	for _, m := range members {
+		if !m.hasData {
+			return Baggage{}, errInvalidMember
+		}
+
+		// OpenTelemetry resolves duplicates by last-one-wins.
+		b[m.key] = baggage.Item{
+			Value:      m.value,
+			Properties: m.properties.asInternal(),
+		}
+	}
+
+	// Check member numbers after deduplication.
+	if len(b) > maxMembers {
+		return Baggage{}, errMemberNumber
+	}
+
+	bag := Baggage{b}
+	if n := len(bag.String()); n > maxBytesPerBaggageString {
+		return Baggage{}, fmt.Errorf("%w: %d", errBaggageBytes, n)
+	}
+
+	return bag, nil
+}
+
+// Parse attempts to decode a baggage-string from the passed string. It
+// returns an error if the input is invalid according to the W3C Baggage
+// specification.
+//
+// If there are duplicate list-members contained in baggage, the last one
+// defined (reading left-to-right) will be the only one kept. This diverges
+// from the W3C Baggage specification which allows duplicate list-members, but
+// conforms to the OpenTelemetry Baggage specification.
+func Parse(bStr string) (Baggage, error) {
+	if bStr == "" {
+		return Baggage{}, nil
+	}
+
+	if n := len(bStr); n > maxBytesPerBaggageString {
+		return Baggage{}, fmt.Errorf("%w: %d", errBaggageBytes, n)
+	}
+
+	b := make(baggage.List)
+	for _, memberStr := range strings.Split(bStr, listDelimiter) {
+		m, err := parseMember(memberStr)
+		if err != nil {
+			return Baggage{}, err
+		}
+		// OpenTelemetry resolves duplicates by last-one-wins.
+		b[m.key] = baggage.Item{
+			Value:      m.value,
+			Properties: m.properties.asInternal(),
+		}
+	}
+
+	// OpenTelemetry does not allow for duplicate list-members, but the W3C
+	// specification does. Now that we have deduplicated, ensure the baggage
+	// does not exceed list-member limits.
+	if len(b) > maxMembers {
+		return Baggage{}, errMemberNumber
+	}
+
+	return Baggage{b}, nil
+}
+
+// Member returns the baggage list-member identified by key.
+//
+// If there is no list-member matching the passed key the returned Member will
+// be a zero-value Member.
+// The returned member is not validated, as we assume the validation happened
+// when it was added to the Baggage.
+func (b Baggage) Member(key string) Member {
+	v, ok := b.list[key]
+	if !ok {
+		// We do not need to worry about distinguishing between the situation
+		// where a zero-valued Member is included in the Baggage because a
+		// zero-valued Member is invalid according to the W3C Baggage
+		// specification (it has an empty key).
+		return newInvalidMember()
+	}
+
+	return Member{
+		key:        key,
+		value:      v.Value,
+		properties: fromInternalProperties(v.Properties),
+		hasData:    true,
+	}
+}
+
+// Members returns all the baggage list-members.
+// The order of the returned list-members does not have significance.
+//
+// The returned members are not validated, as we assume the validation happened
+// when they were added to the Baggage.
+func (b Baggage) Members() []Member {
+	if len(b.list) == 0 {
+		return nil
+	}
+
+	members := make([]Member, 0, len(b.list))
+	for k, v := range b.list {
+		members = append(members, Member{
+			key:        k,
+			value:      v.Value,
+			properties: fromInternalProperties(v.Properties),
+			hasData:    true,
+		})
+	}
+	return members
+}
+
+// SetMember returns a copy the Baggage with the member included. If the
+// baggage contains a Member with the same key the existing Member is
+// replaced.
+//
+// If member is invalid according to the W3C Baggage specification, an error
+// is returned with the original Baggage.
+func (b Baggage) SetMember(member Member) (Baggage, error) {
+	if !member.hasData {
+		return b, errInvalidMember
+	}
+
+	n := len(b.list)
+	if _, ok := b.list[member.key]; !ok {
+		n++
+	}
+	list := make(baggage.List, n)
+
+	for k, v := range b.list {
+		// Do not copy if we are just going to overwrite.
+		if k == member.key {
+			continue
+		}
+		list[k] = v
+	}
+
+	list[member.key] = baggage.Item{
+		Value:      member.value,
+		Properties: member.properties.asInternal(),
+	}
+
+	return Baggage{list: list}, nil
+}
+
+// DeleteMember returns a copy of the Baggage with the list-member identified
+// by key removed.
+func (b Baggage) DeleteMember(key string) Baggage {
+	n := len(b.list)
+	if _, ok := b.list[key]; ok {
+		n--
+	}
+	list := make(baggage.List, n)
+
+	for k, v := range b.list {
+		if k == key {
+			continue
+		}
+		list[k] = v
+	}
+
+	return Baggage{list: list}
+}
+
+// Len returns the number of list-members in the Baggage.
+func (b Baggage) Len() int {
+	return len(b.list)
+}
+
+// String encodes Baggage into a string compliant with the W3C Baggage
+// specification. The returned string will be invalid if the Baggage contains
+// any invalid list-members.
+func (b Baggage) String() string {
+	members := make([]string, 0, len(b.list))
+	for k, v := range b.list {
+		members = append(members, Member{
+			key:        k,
+			value:      v.Value,
+			properties: fromInternalProperties(v.Properties),
+		}.String())
+	}
+	return strings.Join(members, listDelimiter)
+}

+ 844 - 0
pkg/go.opentelemetry.io/otel/baggage/baggage_test.go

@@ -0,0 +1,844 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package baggage
+
+import (
+	"fmt"
+	"math/rand"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"go.opentelemetry.io/otel/internal/baggage"
+)
+
+var rng *rand.Rand
+
+func init() {
+	// Seed with a static value to ensure deterministic results.
+	rng = rand.New(rand.NewSource(1))
+}
+
+func TestKeyRegExp(t *testing.T) {
+	// ASCII only
+	invalidKeyRune := []rune{
+		'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+		'\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F',
+		'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+		'\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F', ' ',
+		'(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?',
+		'=', '{', '}', '\x7F',
+	}
+
+	for _, ch := range invalidKeyRune {
+		assert.NotRegexp(t, keyDef, fmt.Sprintf("%c", ch))
+	}
+}
+
+func TestValueRegExp(t *testing.T) {
+	// ASCII only
+	invalidValueRune := []rune{
+		'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+		'\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F',
+		'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+		'\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F', ' ',
+		'"', ',', ';', '\\', '\x7F',
+	}
+
+	for _, ch := range invalidValueRune {
+		assert.NotRegexp(t, `^`+valueDef+`$`, fmt.Sprintf("invalid-%c-value", ch))
+	}
+}
+
+func TestParseProperty(t *testing.T) {
+	p := Property{key: "key", value: "value", hasValue: true}
+
+	testcases := []struct {
+		in       string
+		expected Property
+	}{
+		{
+			in:       "",
+			expected: Property{},
+		},
+		{
+			in: "key",
+			expected: Property{
+				key: "key",
+			},
+		},
+		{
+			in: "key=",
+			expected: Property{
+				key:      "key",
+				hasValue: true,
+			},
+		},
+		{
+			in:       "key=value",
+			expected: p,
+		},
+		{
+			in:       " key=value ",
+			expected: p,
+		},
+		{
+			in:       "key = value",
+			expected: p,
+		},
+		{
+			in:       " key = value ",
+			expected: p,
+		},
+		{
+			in:       "\tkey=value",
+			expected: p,
+		},
+	}
+
+	for _, tc := range testcases {
+		actual, err := parseProperty(tc.in)
+
+		if !assert.NoError(t, err) {
+			continue
+		}
+
+		assert.Equal(t, tc.expected.Key(), actual.Key(), tc.in)
+
+		actualV, actualOk := actual.Value()
+		expectedV, expectedOk := tc.expected.Value()
+		assert.Equal(t, expectedOk, actualOk, tc.in)
+		assert.Equal(t, expectedV, actualV, tc.in)
+	}
+}
+
+func TestParsePropertyError(t *testing.T) {
+	_, err := parseProperty(",;,")
+	assert.ErrorIs(t, err, errInvalidProperty)
+}
+
+func TestNewKeyProperty(t *testing.T) {
+	p, err := NewKeyProperty(" ")
+	assert.ErrorIs(t, err, errInvalidKey)
+	assert.Equal(t, Property{}, p)
+
+	p, err = NewKeyProperty("key")
+	assert.NoError(t, err)
+	assert.Equal(t, Property{key: "key"}, p)
+}
+
+func TestNewKeyValueProperty(t *testing.T) {
+	p, err := NewKeyValueProperty(" ", "")
+	assert.ErrorIs(t, err, errInvalidKey)
+	assert.Equal(t, Property{}, p)
+
+	p, err = NewKeyValueProperty("key", ";")
+	assert.ErrorIs(t, err, errInvalidValue)
+	assert.Equal(t, Property{}, p)
+
+	p, err = NewKeyValueProperty("key", "value")
+	assert.NoError(t, err)
+	assert.Equal(t, Property{key: "key", value: "value", hasValue: true}, p)
+}
+
+func TestPropertyValidate(t *testing.T) {
+	p := Property{}
+	assert.ErrorIs(t, p.validate(), errInvalidKey)
+
+	p.key = "k"
+	assert.NoError(t, p.validate())
+
+	p.value = ";"
+	assert.EqualError(t, p.validate(), "invalid property: inconsistent value")
+
+	p.hasValue = true
+	assert.ErrorIs(t, p.validate(), errInvalidValue)
+
+	p.value = "v"
+	assert.NoError(t, p.validate())
+}
+
+func TestNewEmptyBaggage(t *testing.T) {
+	b, err := New()
+	assert.NoError(t, err)
+	assert.Equal(t, Baggage{}, b)
+}
+
+func TestNewBaggage(t *testing.T) {
+	b, err := New(Member{key: "k", hasData: true})
+	assert.NoError(t, err)
+	assert.Equal(t, Baggage{list: baggage.List{"k": {}}}, b)
+}
+
+func TestNewBaggageWithDuplicates(t *testing.T) {
+	// Having this many members would normally cause this to error, but since
+	// these are duplicates of the same key they will be collapsed into a
+	// single entry.
+	m := make([]Member, maxMembers+1)
+	for i := range m {
+		// Duplicates are collapsed.
+		m[i] = Member{
+			key:     "a",
+			value:   fmt.Sprintf("%d", i),
+			hasData: true,
+		}
+	}
+	b, err := New(m...)
+	assert.NoError(t, err)
+
+	// Ensure that the last-one-wins by verifying the value.
+	v := fmt.Sprintf("%d", maxMembers)
+	want := Baggage{list: baggage.List{"a": {Value: v}}}
+	assert.Equal(t, want, b)
+}
+
+func TestNewBaggageErrorEmptyMember(t *testing.T) {
+	_, err := New(Member{})
+	assert.ErrorIs(t, err, errInvalidMember)
+}
+
+func key(n int) string {
+	r := []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+
+	b := make([]rune, n)
+	for i := range b {
+		b[i] = r[rng.Intn(len(r))]
+	}
+	return string(b)
+}
+
+func TestNewBaggageErrorTooManyBytes(t *testing.T) {
+	m := make([]Member, (maxBytesPerBaggageString/maxBytesPerMembers)+1)
+	for i := range m {
+		m[i] = Member{key: key(maxBytesPerMembers), hasData: true}
+	}
+	_, err := New(m...)
+	assert.ErrorIs(t, err, errBaggageBytes)
+}
+
+func TestNewBaggageErrorTooManyMembers(t *testing.T) {
+	m := make([]Member, maxMembers+1)
+	for i := range m {
+		m[i] = Member{key: fmt.Sprintf("%d", i), hasData: true}
+	}
+	_, err := New(m...)
+	assert.ErrorIs(t, err, errMemberNumber)
+}
+
+func TestBaggageParse(t *testing.T) {
+	tooLarge := key(maxBytesPerBaggageString + 1)
+
+	tooLargeMember := key(maxBytesPerMembers + 1)
+
+	m := make([]string, maxMembers+1)
+	for i := range m {
+		m[i] = fmt.Sprintf("a%d=", i)
+	}
+	tooManyMembers := strings.Join(m, listDelimiter)
+
+	testcases := []struct {
+		name string
+		in   string
+		want baggage.List
+		err  error
+	}{
+		{
+			name: "empty value",
+			in:   "",
+			want: baggage.List(nil),
+		},
+		{
+			name: "single member empty value no properties",
+			in:   "foo=",
+			want: baggage.List{
+				"foo": {Value: ""},
+			},
+		},
+		{
+			name: "single member no properties",
+			in:   "foo=1",
+			want: baggage.List{
+				"foo": {Value: "1"},
+			},
+		},
+		{
+			name: "single member with spaces",
+			in:   " foo \t= 1\t\t ",
+			want: baggage.List{
+				"foo": {Value: "1"},
+			},
+		},
+		{
+			name: "single member empty value with properties",
+			in:   "foo=;state=on;red",
+			want: baggage.List{
+				"foo": {
+					Value: "",
+					Properties: []baggage.Property{
+						{Key: "state", Value: "on", HasValue: true},
+						{Key: "red"},
+					},
+				},
+			},
+		},
+		{
+			name: "single member with properties",
+			in:   "foo=1;state=on;red",
+			want: baggage.List{
+				"foo": {
+					Value: "1",
+					Properties: []baggage.Property{
+						{Key: "state", Value: "on", HasValue: true},
+						{Key: "red"},
+					},
+				},
+			},
+		},
+		{
+			name: "single member with value containing equal signs",
+			in:   "foo=0=0=0",
+			want: baggage.List{
+				"foo": {Value: "0=0=0"},
+			},
+		},
+		{
+			name: "two members with properties",
+			in:   "foo=1;state=on;red,bar=2;yellow",
+			want: baggage.List{
+				"foo": {
+					Value: "1",
+					Properties: []baggage.Property{
+						{Key: "state", Value: "on", HasValue: true},
+						{Key: "red"},
+					},
+				},
+				"bar": {
+					Value:      "2",
+					Properties: []baggage.Property{{Key: "yellow"}},
+				},
+			},
+		},
+		{
+			// According to the OTel spec, last value wins.
+			name: "duplicate key",
+			in:   "foo=1;state=on;red,foo=2",
+			want: baggage.List{
+				"foo": {Value: "2"},
+			},
+		},
+		{
+			name: "url encoded value",
+			in:   "key1=val%252",
+			want: baggage.List{
+				"key1": {Value: "val%2"},
+			},
+		},
+		{
+			name: "invalid member: empty",
+			in:   "foo=,,bar=",
+			err:  errInvalidMember,
+		},
+		{
+			name: "invalid member: no key",
+			in:   "=foo",
+			err:  errInvalidKey,
+		},
+		{
+			name: "invalid member: no value",
+			in:   "foo",
+			err:  errInvalidMember,
+		},
+		{
+			name: "invalid member: invalid key",
+			in:   "\\=value",
+			err:  errInvalidKey,
+		},
+		{
+			name: "invalid member: invalid value",
+			in:   "foo=\\",
+			err:  errInvalidValue,
+		},
+		{
+			name: "invalid property: invalid key",
+			in:   "foo=1;=v",
+			err:  errInvalidProperty,
+		},
+		{
+			name: "invalid property: invalid value",
+			in:   "foo=1;key=\\",
+			err:  errInvalidProperty,
+		},
+		{
+			name: "invalid baggage string: too large",
+			in:   tooLarge,
+			err:  errBaggageBytes,
+		},
+		{
+			name: "invalid baggage string: member too large",
+			in:   tooLargeMember,
+			err:  errMemberBytes,
+		},
+		{
+			name: "invalid baggage string: too many members",
+			in:   tooManyMembers,
+			err:  errMemberNumber,
+		},
+	}
+
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			actual, err := Parse(tc.in)
+			assert.ErrorIs(t, err, tc.err)
+			assert.Equal(t, Baggage{list: tc.want}, actual)
+		})
+	}
+}
+
+func TestBaggageString(t *testing.T) {
+	testcases := []struct {
+		name    string
+		out     string
+		baggage baggage.List
+	}{
+		{
+			name:    "empty value",
+			out:     "",
+			baggage: baggage.List(nil),
+		},
+		{
+			name: "single member empty value no properties",
+			out:  "foo=",
+			baggage: baggage.List{
+				"foo": {Value: ""},
+			},
+		},
+		{
+			name: "single member no properties",
+			out:  "foo=1",
+			baggage: baggage.List{
+				"foo": {Value: "1"},
+			},
+		},
+		{
+			name: "URL encoded value",
+			out:  "foo=1%3D1",
+			baggage: baggage.List{
+				"foo": {Value: "1=1"},
+			},
+		},
+		{
+			name: "single member empty value with properties",
+			out:  "foo=;red;state=on",
+			baggage: baggage.List{
+				"foo": {
+					Value: "",
+					Properties: []baggage.Property{
+						{Key: "state", Value: "on", HasValue: true},
+						{Key: "red"},
+					},
+				},
+			},
+		},
+		{
+			name: "single member with properties",
+			// Properties are "opaque values" meaning they are sent as they
+			// are set and no encoding is performed.
+			out: "foo=1;red;state=on;z=z=z",
+			baggage: baggage.List{
+				"foo": {
+					Value: "1",
+					Properties: []baggage.Property{
+						{Key: "state", Value: "on", HasValue: true},
+						{Key: "red"},
+						{Key: "z", Value: "z=z", HasValue: true},
+					},
+				},
+			},
+		},
+		{
+			name: "two members with properties",
+			out:  "bar=2;yellow,foo=1;red;state=on",
+			baggage: baggage.List{
+				"foo": {
+					Value: "1",
+					Properties: []baggage.Property{
+						{Key: "state", Value: "on", HasValue: true},
+						{Key: "red"},
+					},
+				},
+				"bar": {
+					Value:      "2",
+					Properties: []baggage.Property{{Key: "yellow"}},
+				},
+			},
+		},
+	}
+
+	orderer := func(s string) string {
+		members := strings.Split(s, listDelimiter)
+		for i, m := range members {
+			parts := strings.Split(m, propertyDelimiter)
+			if len(parts) > 1 {
+				sort.Strings(parts[1:])
+				members[i] = strings.Join(parts, propertyDelimiter)
+			}
+		}
+		sort.Strings(members)
+		return strings.Join(members, listDelimiter)
+	}
+
+	for _, tc := range testcases {
+		b := Baggage{tc.baggage}
+		assert.Equal(t, tc.out, orderer(b.String()))
+	}
+}
+
+func TestBaggageLen(t *testing.T) {
+	b := Baggage{}
+	assert.Equal(t, 0, b.Len())
+
+	b.list = make(baggage.List, 1)
+	assert.Equal(t, 0, b.Len())
+
+	b.list["k"] = baggage.Item{}
+	assert.Equal(t, 1, b.Len())
+}
+
+func TestBaggageDeleteMember(t *testing.T) {
+	key := "k"
+
+	b0 := Baggage{}
+	b1 := b0.DeleteMember(key)
+	assert.NotContains(t, b1.list, key)
+
+	b0 = Baggage{list: baggage.List{
+		key:     {},
+		"other": {},
+	}}
+	b1 = b0.DeleteMember(key)
+	assert.Contains(t, b0.list, key)
+	assert.NotContains(t, b1.list, key)
+}
+
+func TestBaggageSetMemberEmpty(t *testing.T) {
+	_, err := Baggage{}.SetMember(Member{})
+	assert.ErrorIs(t, err, errInvalidMember)
+}
+
+func TestBaggageSetMember(t *testing.T) {
+	b0 := Baggage{}
+
+	key := "k"
+	m := Member{key: key, hasData: true}
+	b1, err := b0.SetMember(m)
+	assert.NoError(t, err)
+	assert.NotContains(t, b0.list, key)
+	assert.Equal(t, baggage.Item{}, b1.list[key])
+	assert.Equal(t, 0, len(b0.list))
+	assert.Equal(t, 1, len(b1.list))
+
+	m.value = "v"
+	b2, err := b1.SetMember(m)
+	assert.NoError(t, err)
+	assert.Equal(t, baggage.Item{}, b1.list[key])
+	assert.Equal(t, baggage.Item{Value: "v"}, b2.list[key])
+	assert.Equal(t, 1, len(b1.list))
+	assert.Equal(t, 1, len(b2.list))
+
+	p := properties{{key: "p"}}
+	m.properties = p
+	b3, err := b2.SetMember(m)
+	assert.NoError(t, err)
+	assert.Equal(t, baggage.Item{Value: "v"}, b2.list[key])
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b3.list[key])
+	assert.Equal(t, 1, len(b2.list))
+	assert.Equal(t, 1, len(b3.list))
+
+	// The returned baggage needs to be immutable and should use a copy of the
+	// properties slice.
+	p[0] = Property{key: "different"}
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b3.list[key])
+	// Reset for below.
+	p[0] = Property{key: "p"}
+
+	m = Member{key: "another", hasData: true}
+	b4, err := b3.SetMember(m)
+	assert.NoError(t, err)
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b3.list[key])
+	assert.NotContains(t, b3.list, m.key)
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b4.list[key])
+	assert.Equal(t, baggage.Item{}, b4.list[m.key])
+	assert.Equal(t, 1, len(b3.list))
+	assert.Equal(t, 2, len(b4.list))
+}
+
+func TestBaggageSetFalseMember(t *testing.T) {
+	b0 := Baggage{}
+
+	key := "k"
+	m := Member{key: key, hasData: false}
+	b1, err := b0.SetMember(m)
+	assert.Error(t, err)
+	assert.NotContains(t, b0.list, key)
+	assert.Equal(t, baggage.Item{}, b1.list[key])
+	assert.Equal(t, 0, len(b0.list))
+	assert.Equal(t, 0, len(b1.list))
+
+	m.value = "v"
+	b2, err := b1.SetMember(m)
+	assert.Error(t, err)
+	assert.Equal(t, baggage.Item{}, b1.list[key])
+	assert.Equal(t, baggage.Item{Value: ""}, b2.list[key])
+	assert.Equal(t, 0, len(b1.list))
+	assert.Equal(t, 0, len(b2.list))
+}
+
+func TestBaggageSetFalseMembers(t *testing.T) {
+	b0 := Baggage{}
+
+	key := "k"
+	m := Member{key: key, hasData: true}
+	b1, err := b0.SetMember(m)
+	assert.NoError(t, err)
+	assert.NotContains(t, b0.list, key)
+	assert.Equal(t, baggage.Item{}, b1.list[key])
+	assert.Equal(t, 0, len(b0.list))
+	assert.Equal(t, 1, len(b1.list))
+
+	m.value = "v"
+	b2, err := b1.SetMember(m)
+	assert.NoError(t, err)
+	assert.Equal(t, baggage.Item{}, b1.list[key])
+	assert.Equal(t, baggage.Item{Value: "v"}, b2.list[key])
+	assert.Equal(t, 1, len(b1.list))
+	assert.Equal(t, 1, len(b2.list))
+
+	p := properties{{key: "p"}}
+	m.properties = p
+	b3, err := b2.SetMember(m)
+	assert.NoError(t, err)
+	assert.Equal(t, baggage.Item{Value: "v"}, b2.list[key])
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b3.list[key])
+	assert.Equal(t, 1, len(b2.list))
+	assert.Equal(t, 1, len(b3.list))
+
+	// The returned baggage needs to be immutable and should use a copy of the
+	// properties slice.
+	p[0] = Property{key: "different"}
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b3.list[key])
+	// Reset for below.
+	p[0] = Property{key: "p"}
+
+	m = Member{key: "another"}
+	b4, err := b3.SetMember(m)
+	assert.Error(t, err)
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b3.list[key])
+	assert.NotContains(t, b3.list, m.key)
+	assert.Equal(t, baggage.Item{Value: "v", Properties: []baggage.Property{{Key: "p"}}}, b4.list[key])
+	assert.Equal(t, baggage.Item{}, b4.list[m.key])
+	assert.Equal(t, 1, len(b3.list))
+	assert.Equal(t, 1, len(b4.list))
+}
+
+func TestNilBaggageMembers(t *testing.T) {
+	assert.Nil(t, Baggage{}.Members())
+}
+
+func TestBaggageMembers(t *testing.T) {
+	members := []Member{
+		{
+			key:   "foo",
+			value: "1",
+			properties: properties{
+				{key: "state", value: "on", hasValue: true},
+				{key: "red"},
+			},
+			hasData: true,
+		},
+		{
+			key:   "bar",
+			value: "2",
+			properties: properties{
+				{key: "yellow"},
+			},
+			hasData: true,
+		},
+	}
+
+	bag := Baggage{list: baggage.List{
+		"foo": {
+			Value: "1",
+			Properties: []baggage.Property{
+				{Key: "state", Value: "on", HasValue: true},
+				{Key: "red"},
+			},
+		},
+		"bar": {
+			Value:      "2",
+			Properties: []baggage.Property{{Key: "yellow"}},
+		},
+	}}
+
+	assert.ElementsMatch(t, members, bag.Members())
+}
+
+func TestBaggageMember(t *testing.T) {
+	bag := Baggage{list: baggage.List{"foo": {Value: "1"}}}
+	assert.Equal(t, Member{key: "foo", value: "1", hasData: true}, bag.Member("foo"))
+	assert.Equal(t, Member{}, bag.Member("bar"))
+}
+
+func TestMemberKey(t *testing.T) {
+	m := Member{}
+	assert.Equal(t, "", m.Key(), "even invalid values should be returned")
+
+	key := "k"
+	m.key = key
+	assert.Equal(t, key, m.Key())
+}
+
+func TestMemberValue(t *testing.T) {
+	m := Member{key: "k", value: "\\"}
+	assert.Equal(t, "\\", m.Value(), "even invalid values should be returned")
+
+	value := "v"
+	m.value = value
+	assert.Equal(t, value, m.Value())
+}
+
+func TestMemberProperties(t *testing.T) {
+	m := Member{key: "k", value: "v"}
+	assert.Nil(t, m.Properties())
+
+	p := []Property{{key: "foo"}}
+	m.properties = properties(p)
+	got := m.Properties()
+	assert.Equal(t, p, got)
+
+	// Returned slice needs to be a copy so the original is immutable.
+	got[0] = Property{key: "bar"}
+	assert.NotEqual(t, m.properties, got)
+}
+
+func TestMemberValidation(t *testing.T) {
+	m := Member{hasData: false}
+	assert.ErrorIs(t, m.validate(), errInvalidMember)
+
+	m.hasData = true
+	assert.ErrorIs(t, m.validate(), errInvalidKey)
+
+	m.key, m.value = "k", "\\"
+	assert.ErrorIs(t, m.validate(), errInvalidValue)
+
+	m.value = "v"
+	assert.NoError(t, m.validate())
+}
+
+func TestNewMember(t *testing.T) {
+	m, err := NewMember("", "")
+	assert.ErrorIs(t, err, errInvalidKey)
+	assert.Equal(t, Member{hasData: false}, m)
+
+	key, val := "k", "v"
+	p := Property{key: "foo"}
+	m, err = NewMember(key, val, p)
+	assert.NoError(t, err)
+	expected := Member{
+		key:        key,
+		value:      val,
+		properties: properties{{key: "foo"}},
+		hasData:    true,
+	}
+	assert.Equal(t, expected, m)
+
+	// wrong value with wrong decoding
+	val = "%zzzzz"
+	_, err = NewMember(key, val, p)
+	assert.ErrorIs(t, err, errInvalidValue)
+
+	// value should be decoded
+	val = "%3B"
+	m, err = NewMember(key, val, p)
+	expected = Member{
+		key:        key,
+		value:      ";",
+		properties: properties{{key: "foo"}},
+		hasData:    true,
+	}
+	assert.NoError(t, err)
+	assert.Equal(t, expected, m)
+
+	// Ensure new member is immutable.
+	p.key = "bar"
+	assert.Equal(t, expected, m)
+}
+
+func TestPropertiesValidate(t *testing.T) {
+	p := properties{{}}
+	assert.ErrorIs(t, p.validate(), errInvalidKey)
+
+	p[0].key = "foo"
+	assert.NoError(t, p.validate())
+
+	p = append(p, Property{key: "bar"})
+	assert.NoError(t, p.validate())
+}
+
+func TestMemberString(t *testing.T) {
+	// normal key value pair
+	member, _ := NewMember("key", "value")
+	memberStr := member.String()
+	assert.Equal(t, memberStr, "key=value")
+	// encoded key
+	member, _ = NewMember("key", "%3B")
+	memberStr = member.String()
+	assert.Equal(t, memberStr, "key=%3B")
+}
+
+var benchBaggage Baggage
+
+func BenchmarkNew(b *testing.B) {
+	mem1, _ := NewMember("key1", "val1")
+	mem2, _ := NewMember("key2", "val2")
+	mem3, _ := NewMember("key3", "val3")
+	mem4, _ := NewMember("key4", "val4")
+
+	b.ReportAllocs()
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		benchBaggage, _ = New(mem1, mem2, mem3, mem4)
+	}
+}
+
+var benchMember Member
+
+func BenchmarkNewMember(b *testing.B) {
+	b.ReportAllocs()
+
+	for i := 0; i < b.N; i++ {
+		benchMember, _ = NewMember("key", "value")
+	}
+}
+
+func BenchmarkParse(b *testing.B) {
+	b.ReportAllocs()
+
+	for i := 0; i < b.N; i++ {
+		benchBaggage, _ = Parse(`userId=alice,serverNode = DF28 , isProduction = false,hasProp=stuff;propKey;propWValue=value`)
+	}
+}

+ 39 - 0
pkg/go.opentelemetry.io/otel/baggage/context.go

@@ -0,0 +1,39 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package baggage // import "go.opentelemetry.io/otel/baggage"
+
+import (
+	"context"
+
+	"go.opentelemetry.io/otel/internal/baggage"
+)
+
+// ContextWithBaggage returns a copy of parent with baggage.
+func ContextWithBaggage(parent context.Context, b Baggage) context.Context {
+	// Delegate so any hooks for the OpenTracing bridge are handled.
+	return baggage.ContextWithList(parent, b.list)
+}
+
+// ContextWithoutBaggage returns a copy of parent with no baggage.
+func ContextWithoutBaggage(parent context.Context) context.Context {
+	// Delegate so any hooks for the OpenTracing bridge are handled.
+	return baggage.ContextWithList(parent, nil)
+}
+
+// FromContext returns the baggage contained in ctx.
+func FromContext(ctx context.Context) Baggage {
+	// Delegate so any hooks for the OpenTracing bridge are handled.
+	return Baggage{list: baggage.ListFromContext(ctx)}
+}

+ 36 - 0
pkg/go.opentelemetry.io/otel/baggage/context_test.go

@@ -0,0 +1,36 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package baggage
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"go.opentelemetry.io/otel/internal/baggage"
+)
+
+func TestContext(t *testing.T) {
+	ctx := context.Background()
+	assert.Equal(t, Baggage{}, FromContext(ctx))
+
+	b := Baggage{list: baggage.List{"key": baggage.Item{Value: "val"}}}
+	ctx = ContextWithBaggage(ctx, b)
+	assert.Equal(t, b, FromContext(ctx))
+
+	ctx = ContextWithoutBaggage(ctx)
+	assert.Equal(t, Baggage{}, FromContext(ctx))
+}

+ 20 - 0
pkg/go.opentelemetry.io/otel/baggage/doc.go

@@ -0,0 +1,20 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+Package baggage provides functionality for storing and retrieving
+baggage items in Go context. For propagating the baggage, see the
+go.opentelemetry.io/otel/propagation package.
+*/
+package baggage // import "go.opentelemetry.io/otel/baggage"

+ 63 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/doc.go

@@ -0,0 +1,63 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package opencensus provides a migration bridge from OpenCensus to
+// OpenTelemetry for metrics and traces. The bridge incorporates metrics and
+// traces from OpenCensus into the OpenTelemetry SDK, combining them with
+// metrics and traces from OpenTelemetry instrumentation.
+//
+// # Migration Guide
+//
+// For most applications, it would be difficult to migrate an application
+// from OpenCensus to OpenTelemetry all-at-once. Libraries used by the
+// application may still be using OpenCensus, and the application itself may
+// have many lines of instrumentation.
+//
+// Bridges help in this situation by allowing your application to have "mixed"
+// instrumentation, while incorporating all instrumentation into a single
+// export path. To migrate with bridges, a user would:
+//
+//  1. Configure the OpenTelemetry SDK for metrics and traces, with the OpenTelemetry exporters matching to your current OpenCensus exporters.
+//  2. Install this OpenCensus bridge, which sends OpenCensus telemetry to your new OpenTelemetry exporters.
+//  3. Over time, migrate your instrumentation from OpenCensus to OpenTelemetry.
+//  4. Once all instrumentation is migrated, remove the OpenCensus bridge.
+//
+// With this approach, you can migrate your telemetry, including in dependent
+// libraries over time without disruption.
+//
+// # Warnings
+//
+// Installing a metric or tracing bridge will cause OpenCensus telemetry to be
+// exported by OpenTelemetry exporters. Since OpenCensus telemetry uses globals,
+// installing a bridge will result in telemetry collection from _all_ libraries
+// that use OpenCensus, including some you may not expect, such as the
+// telemetry exporter itself.
+//
+// # Limitations
+//
+// There are known limitations to the trace bridge:
+//
+//   - The AddLink method for OpenCensus Spans is ignored, and an error is sent
+//     to the OpenTelemetry ErrorHandler.
+//   - The NewContext method of the OpenCensus Tracer cannot embed an OpenCensus
+//     Span in a context unless that Span was created by that Tracer.
+//   - Conversion of custom OpenCensus Samplers to OpenTelemetry is not
+//     implemented, and An error will be sent to the OpenTelemetry ErrorHandler.
+//
+// There are known limitations to the metric bridge:
+//   - Summary-typed metrics are dropped
+//   - GaugeDistribution-typed metrics are dropped
+//   - Histogram's SumOfSquaredDeviation field is dropped
+//   - Exemplars on Histograms are dropped
+package opencensus // import "go.opentelemetry.io/otel/bridge/opencensus"

+ 44 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/example_test.go

@@ -0,0 +1,44 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opencensus_test
+
+import (
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/bridge/opencensus"
+	"go.opentelemetry.io/otel/sdk/metric"
+)
+
+func ExampleNewTracer() {
+	// Create an OpenTelemetry Tracer to use to record spans.
+	tracer := otel.GetTracerProvider().Tracer("go.opentelemetry.io/otel/bridge/opencensus")
+	// Overwrite the OpenCensus DefaultTracer so that it uses OpenTelemetry
+	// rather than OpenCensus.
+	octrace.DefaultTracer = opencensus.NewTracer(tracer)
+}
+
+func ExampleNewMetricProducer() {
+	// Create the OpenCensus Metric bridge.
+	bridge := opencensus.NewMetricProducer()
+	// Add the bridge as a producer to your reader.
+	// If using a push exporter, such as OTLP exporter,
+	// use metric.NewPeriodicReader with metric.WithProducer option.
+	// If using a pull exporter which acts as a reader, such as prometheus exporter,
+	// use a dedicated option like prometheus.WithProducer.
+	reader := metric.NewManualReader(metric.WithProducer(bridge))
+	// Add the reader to your MeterProvider.
+	_ = metric.NewMeterProvider(metric.WithReader(reader))
+}

+ 35 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/go.mod

@@ -0,0 +1,35 @@
+module go.opentelemetry.io/otel/bridge/opencensus
+
+go 1.20
+
+require (
+	github.com/stretchr/testify v1.8.4
+	go.opencensus.io v0.24.0
+	go.opentelemetry.io/otel v1.19.0
+	go.opentelemetry.io/otel/sdk v1.19.0
+	go.opentelemetry.io/otel/sdk/metric v1.19.0
+	go.opentelemetry.io/otel/trace v1.19.0
+)
+
+require (
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/go-logr/logr v1.2.4 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
+	github.com/kr/pretty v0.1.0 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	go.opentelemetry.io/otel/metric v1.19.0 // indirect
+	golang.org/x/sys v0.12.0 // indirect
+	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
+
+replace go.opentelemetry.io/otel => ../..
+
+replace go.opentelemetry.io/otel/trace => ../../trace
+
+replace go.opentelemetry.io/otel/sdk => ../../sdk
+
+replace go.opentelemetry.io/otel/metric => ../../metric
+
+replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

+ 113 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/go.sum

@@ -0,0 +1,113 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 21 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/handler.go

@@ -0,0 +1,21 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opentelemetry.io/otel/bridge/opencensus/internal"
+
+import "go.opentelemetry.io/otel"
+
+// Handle is the package level function to handle errors. It can be
+// overwritten for testing.
+var Handle = otel.Handle

+ 47 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/attributes.go

@@ -0,0 +1,47 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package oc2otel // import "go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+
+import (
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+func Attributes(attr []octrace.Attribute) []attribute.KeyValue {
+	otelAttr := make([]attribute.KeyValue, len(attr))
+	for i, a := range attr {
+		otelAttr[i] = attribute.KeyValue{
+			Key:   attribute.Key(a.Key()),
+			Value: AttributeValue(a.Value()),
+		}
+	}
+	return otelAttr
+}
+
+func AttributeValue(ocval interface{}) attribute.Value {
+	switch v := ocval.(type) {
+	case bool:
+		return attribute.BoolValue(v)
+	case int64:
+		return attribute.Int64Value(v)
+	case float64:
+		return attribute.Float64Value(v)
+	case string:
+		return attribute.StringValue(v)
+	default:
+		return attribute.StringValue("unknown")
+	}
+}

+ 56 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/attributes_test.go

@@ -0,0 +1,56 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package oc2otel
+
+import (
+	"testing"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/attribute"
+)
+
+func TestAttributes(t *testing.T) {
+	in := []octrace.Attribute{
+		octrace.BoolAttribute("bool", true),
+		octrace.Int64Attribute("int64", 49),
+		octrace.Float64Attribute("float64", 1.618),
+		octrace.StringAttribute("key", "val"),
+	}
+
+	want := []attribute.KeyValue{
+		attribute.Bool("bool", true),
+		attribute.Int64("int64", 49),
+		attribute.Float64("float64", 1.618),
+		attribute.String("key", "val"),
+	}
+	got := Attributes(in)
+
+	if len(got) != len(want) {
+		t.Errorf("Attributes conversion failed: want %#v, got %#v", want, got)
+	}
+	for i := range got {
+		if g, w := got[i], want[i]; g != w {
+			t.Errorf("Attributes conversion: want %#v, got %#v", w, g)
+		}
+	}
+}
+
+func TestAttributeValueUnknown(t *testing.T) {
+	got := AttributeValue([]byte{})
+	if got != attribute.StringValue("unknown") {
+		t.Errorf("AttributeValue of unknown wrong: %#v", got)
+	}
+}

+ 33 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/span_context.go

@@ -0,0 +1,33 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package oc2otel // import "go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+
+import (
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+func SpanContext(sc octrace.SpanContext) trace.SpanContext {
+	var traceFlags trace.TraceFlags
+	if sc.IsSampled() {
+		traceFlags = trace.FlagsSampled
+	}
+	return trace.NewSpanContext(trace.SpanContextConfig{
+		TraceID:    trace.TraceID(sc.TraceID),
+		SpanID:     trace.SpanID(sc.SpanID),
+		TraceFlags: traceFlags,
+	})
+}

+ 80 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/span_context_test.go

@@ -0,0 +1,80 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package oc2otel
+
+import (
+	"testing"
+
+	octrace "go.opencensus.io/trace"
+	"go.opencensus.io/trace/tracestate"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+func TestSpanContextConversion(t *testing.T) {
+	for _, tc := range []struct {
+		description string
+		input       octrace.SpanContext
+		expected    trace.SpanContext
+	}{
+		{
+			description: "empty",
+		},
+		{
+			description: "sampled",
+			input: octrace.SpanContext{
+				TraceID:      octrace.TraceID([16]byte{1}),
+				SpanID:       octrace.SpanID([8]byte{2}),
+				TraceOptions: octrace.TraceOptions(0x1),
+			},
+			expected: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    trace.TraceID([16]byte{1}),
+				SpanID:     trace.SpanID([8]byte{2}),
+				TraceFlags: trace.FlagsSampled,
+			}),
+		},
+		{
+			description: "not sampled",
+			input: octrace.SpanContext{
+				TraceID:      octrace.TraceID([16]byte{1}),
+				SpanID:       octrace.SpanID([8]byte{2}),
+				TraceOptions: octrace.TraceOptions(0),
+			},
+			expected: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: trace.TraceID([16]byte{1}),
+				SpanID:  trace.SpanID([8]byte{2}),
+			}),
+		},
+		{
+			description: "trace state is ignored",
+			input: octrace.SpanContext{
+				TraceID:    octrace.TraceID([16]byte{1}),
+				SpanID:     octrace.SpanID([8]byte{2}),
+				Tracestate: &tracestate.Tracestate{},
+			},
+			expected: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: trace.TraceID([16]byte{1}),
+				SpanID:  trace.SpanID([8]byte{2}),
+			}),
+		},
+	} {
+		t.Run(tc.description, func(t *testing.T) {
+			output := SpanContext(tc.input)
+			if !output.Equal(tc.expected) {
+				t.Fatalf("Got %+v spancontext, expected %+v.", output, tc.expected)
+			}
+		})
+	}
+}

+ 46 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/tracer_start_options.go

@@ -0,0 +1,46 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package oc2otel // import "go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+
+import (
+	"fmt"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+func StartOptions(optFuncs []octrace.StartOption) ([]trace.SpanStartOption, error) {
+	var ocOpts octrace.StartOptions
+	for _, fn := range optFuncs {
+		fn(&ocOpts)
+	}
+
+	var otelOpts []trace.SpanStartOption
+	switch ocOpts.SpanKind {
+	case octrace.SpanKindClient:
+		otelOpts = append(otelOpts, trace.WithSpanKind(trace.SpanKindClient))
+	case octrace.SpanKindServer:
+		otelOpts = append(otelOpts, trace.WithSpanKind(trace.SpanKindServer))
+	case octrace.SpanKindUnspecified:
+		otelOpts = append(otelOpts, trace.WithSpanKind(trace.SpanKindUnspecified))
+	}
+
+	var err error
+	if ocOpts.Sampler != nil {
+		err = fmt.Errorf("unsupported sampler: %v", ocOpts.Sampler)
+	}
+	return otelOpts, err
+}

+ 52 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel/tracer_start_options_test.go

@@ -0,0 +1,52 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package oc2otel
+
+import (
+	"testing"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+func TestStartOptionsSpanKind(t *testing.T) {
+	conv := map[int]trace.SpanKind{
+		octrace.SpanKindClient:      trace.SpanKindClient,
+		octrace.SpanKindServer:      trace.SpanKindServer,
+		octrace.SpanKindUnspecified: trace.SpanKindUnspecified,
+	}
+
+	for oc, otel := range conv {
+		ocOpts := []octrace.StartOption{octrace.WithSpanKind(oc)}
+		otelOpts, err := StartOptions(ocOpts)
+		if err != nil {
+			t.Errorf("StartOptions errored: %v", err)
+			continue
+		}
+		c := trace.NewSpanStartConfig(otelOpts...)
+		if c.SpanKind() != otel {
+			t.Errorf("conversion of SpanKind start option: got %v, want %v", c.SpanKind(), otel)
+		}
+	}
+}
+
+func TestStartOptionsSamplerErrors(t *testing.T) {
+	ocOpts := []octrace.StartOption{octrace.WithSampler(octrace.AlwaysSample())}
+	_, err := StartOptions(ocOpts)
+	if err == nil {
+		t.Error("StartOptions should error Sampler option")
+	}
+}

+ 202 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric/metric.go

@@ -0,0 +1,202 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric"
+
+import (
+	"errors"
+	"fmt"
+
+	ocmetricdata "go.opencensus.io/metric/metricdata"
+
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/sdk/metric/metricdata"
+)
+
+var (
+	errConversion                   = errors.New("converting from OpenCensus to OpenTelemetry")
+	errAggregationType              = errors.New("unsupported OpenCensus aggregation type")
+	errMismatchedValueTypes         = errors.New("wrong value type for data point")
+	errNumberDataPoint              = errors.New("converting a number data point")
+	errHistogramDataPoint           = errors.New("converting a histogram data point")
+	errNegativeDistributionCount    = errors.New("distribution count is negative")
+	errNegativeBucketCount          = errors.New("distribution bucket count is negative")
+	errMismatchedAttributeKeyValues = errors.New("mismatched number of attribute keys and values")
+)
+
+// ConvertMetrics converts metric data from OpenCensus to OpenTelemetry.
+func ConvertMetrics(ocmetrics []*ocmetricdata.Metric) ([]metricdata.Metrics, error) {
+	otelMetrics := make([]metricdata.Metrics, 0, len(ocmetrics))
+	var errInfo []string
+	for _, ocm := range ocmetrics {
+		if ocm == nil {
+			continue
+		}
+		agg, err := convertAggregation(ocm)
+		if err != nil {
+			errInfo = append(errInfo, err.Error())
+			continue
+		}
+		otelMetrics = append(otelMetrics, metricdata.Metrics{
+			Name:        ocm.Descriptor.Name,
+			Description: ocm.Descriptor.Description,
+			Unit:        string(ocm.Descriptor.Unit),
+			Data:        agg,
+		})
+	}
+	var aggregatedError error
+	if len(errInfo) > 0 {
+		aggregatedError = fmt.Errorf("%w: %q", errConversion, errInfo)
+	}
+	return otelMetrics, aggregatedError
+}
+
+// convertAggregation produces an aggregation based on the OpenCensus Metric.
+func convertAggregation(metric *ocmetricdata.Metric) (metricdata.Aggregation, error) {
+	labelKeys := metric.Descriptor.LabelKeys
+	switch metric.Descriptor.Type {
+	case ocmetricdata.TypeGaugeInt64:
+		return convertGauge[int64](labelKeys, metric.TimeSeries)
+	case ocmetricdata.TypeGaugeFloat64:
+		return convertGauge[float64](labelKeys, metric.TimeSeries)
+	case ocmetricdata.TypeCumulativeInt64:
+		return convertSum[int64](labelKeys, metric.TimeSeries)
+	case ocmetricdata.TypeCumulativeFloat64:
+		return convertSum[float64](labelKeys, metric.TimeSeries)
+	case ocmetricdata.TypeCumulativeDistribution:
+		return convertHistogram(labelKeys, metric.TimeSeries)
+		// TODO: Support summaries, once it is in the OTel data types.
+	}
+	return nil, fmt.Errorf("%w: %q", errAggregationType, metric.Descriptor.Type)
+}
+
+// convertGauge converts an OpenCensus gauge to an OpenTelemetry gauge aggregation.
+func convertGauge[N int64 | float64](labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) (metricdata.Gauge[N], error) {
+	points, err := convertNumberDataPoints[N](labelKeys, ts)
+	return metricdata.Gauge[N]{DataPoints: points}, err
+}
+
+// convertSum converts an OpenCensus cumulative to an OpenTelemetry sum aggregation.
+func convertSum[N int64 | float64](labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) (metricdata.Sum[N], error) {
+	points, err := convertNumberDataPoints[N](labelKeys, ts)
+	// OpenCensus sums are always Cumulative
+	return metricdata.Sum[N]{DataPoints: points, Temporality: metricdata.CumulativeTemporality, IsMonotonic: true}, err
+}
+
+// convertNumberDataPoints converts OpenCensus TimeSeries to OpenTelemetry DataPoints.
+func convertNumberDataPoints[N int64 | float64](labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) ([]metricdata.DataPoint[N], error) {
+	var points []metricdata.DataPoint[N]
+	var errInfo []string
+	for _, t := range ts {
+		attrs, err := convertAttrs(labelKeys, t.LabelValues)
+		if err != nil {
+			errInfo = append(errInfo, err.Error())
+			continue
+		}
+		for _, p := range t.Points {
+			v, ok := p.Value.(N)
+			if !ok {
+				errInfo = append(errInfo, fmt.Sprintf("%v: %q", errMismatchedValueTypes, p.Value))
+				continue
+			}
+			points = append(points, metricdata.DataPoint[N]{
+				Attributes: attrs,
+				StartTime:  t.StartTime,
+				Time:       p.Time,
+				Value:      v,
+			})
+		}
+	}
+	var aggregatedError error
+	if len(errInfo) > 0 {
+		aggregatedError = fmt.Errorf("%w: %v", errNumberDataPoint, errInfo)
+	}
+	return points, aggregatedError
+}
+
+// convertHistogram converts OpenCensus Distribution timeseries to an
+// OpenTelemetry Histogram aggregation.
+func convertHistogram(labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) (metricdata.Histogram[float64], error) {
+	points := make([]metricdata.HistogramDataPoint[float64], 0, len(ts))
+	var errInfo []string
+	for _, t := range ts {
+		attrs, err := convertAttrs(labelKeys, t.LabelValues)
+		if err != nil {
+			errInfo = append(errInfo, err.Error())
+			continue
+		}
+		for _, p := range t.Points {
+			dist, ok := p.Value.(*ocmetricdata.Distribution)
+			if !ok {
+				errInfo = append(errInfo, fmt.Sprintf("%v: %d", errMismatchedValueTypes, p.Value))
+				continue
+			}
+			bucketCounts, err := convertBucketCounts(dist.Buckets)
+			if err != nil {
+				errInfo = append(errInfo, err.Error())
+				continue
+			}
+			if dist.Count < 0 {
+				errInfo = append(errInfo, fmt.Sprintf("%v: %d", errNegativeDistributionCount, dist.Count))
+				continue
+			}
+			// TODO: handle exemplars
+			points = append(points, metricdata.HistogramDataPoint[float64]{
+				Attributes:   attrs,
+				StartTime:    t.StartTime,
+				Time:         p.Time,
+				Count:        uint64(dist.Count),
+				Sum:          dist.Sum,
+				Bounds:       dist.BucketOptions.Bounds,
+				BucketCounts: bucketCounts,
+			})
+		}
+	}
+	var aggregatedError error
+	if len(errInfo) > 0 {
+		aggregatedError = fmt.Errorf("%w: %v", errHistogramDataPoint, errInfo)
+	}
+	return metricdata.Histogram[float64]{DataPoints: points, Temporality: metricdata.CumulativeTemporality}, aggregatedError
+}
+
+// convertBucketCounts converts from OpenCensus bucket counts to slice of uint64.
+func convertBucketCounts(buckets []ocmetricdata.Bucket) ([]uint64, error) {
+	bucketCounts := make([]uint64, len(buckets))
+	for i, bucket := range buckets {
+		if bucket.Count < 0 {
+			return nil, fmt.Errorf("%w: %q", errNegativeBucketCount, bucket.Count)
+		}
+		bucketCounts[i] = uint64(bucket.Count)
+	}
+	return bucketCounts, nil
+}
+
+// convertAttrs converts from OpenCensus attribute keys and values to an
+// OpenTelemetry attribute Set.
+func convertAttrs(keys []ocmetricdata.LabelKey, values []ocmetricdata.LabelValue) (attribute.Set, error) {
+	if len(keys) != len(values) {
+		return attribute.NewSet(), fmt.Errorf("%w: keys(%q) values(%q)", errMismatchedAttributeKeyValues, len(keys), len(values))
+	}
+	attrs := []attribute.KeyValue{}
+	for i, lv := range values {
+		if !lv.Present {
+			continue
+		}
+		attrs = append(attrs, attribute.KeyValue{
+			Key:   attribute.Key(keys[i].Key),
+			Value: attribute.StringValue(lv.Value),
+		})
+	}
+	return attribute.NewSet(attrs...), nil
+}

+ 634 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric/metric_test.go

@@ -0,0 +1,634 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opentelemetry.io/otel/bridge/opencensus/opencensusmetric/internal"
+
+import (
+	"errors"
+	"testing"
+	"time"
+
+	ocmetricdata "go.opencensus.io/metric/metricdata"
+
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/sdk/metric/metricdata"
+	"go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest"
+)
+
+func TestConvertMetrics(t *testing.T) {
+	endTime1 := time.Now()
+	endTime2 := endTime1.Add(-time.Millisecond)
+	startTime := endTime2.Add(-time.Minute)
+	for _, tc := range []struct {
+		desc        string
+		input       []*ocmetricdata.Metric
+		expected    []metricdata.Metrics
+		expectedErr error
+	}{
+		{
+			desc:     "empty",
+			expected: []metricdata.Metrics{},
+		},
+		{
+			desc: "normal Histogram, gauges, and sums",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/histogram-a",
+						Description: "a testing histogram",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeCumulativeDistribution,
+						LabelKeys: []ocmetricdata.LabelKey{
+							{Key: "a"},
+							{Key: "b"},
+						},
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+
+							LabelValues: []ocmetricdata.LabelValue{
+								{
+									Value:   "hello",
+									Present: true,
+								}, {
+									Value:   "world",
+									Present: true,
+								},
+							},
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewDistributionPoint(endTime1, &ocmetricdata.Distribution{
+									Count: 8,
+									Sum:   100.0,
+									BucketOptions: &ocmetricdata.BucketOptions{
+										Bounds: []float64{1.0, 2.0, 3.0},
+									},
+									Buckets: []ocmetricdata.Bucket{
+										{Count: 1},
+										{Count: 2},
+										{Count: 5},
+									},
+								}),
+								ocmetricdata.NewDistributionPoint(endTime2, &ocmetricdata.Distribution{
+									Count: 10,
+									Sum:   110.0,
+									BucketOptions: &ocmetricdata.BucketOptions{
+										Bounds: []float64{1.0, 2.0, 3.0},
+									},
+									Buckets: []ocmetricdata.Bucket{
+										{Count: 1},
+										{Count: 4},
+										{Count: 5},
+									},
+								}),
+							},
+							StartTime: startTime,
+						},
+					},
+				}, {
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/gauge-a",
+						Description: "an int testing gauge",
+						Unit:        ocmetricdata.UnitBytes,
+						Type:        ocmetricdata.TypeGaugeInt64,
+						LabelKeys: []ocmetricdata.LabelKey{
+							{Key: "c"},
+							{Key: "d"},
+						},
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							LabelValues: []ocmetricdata.LabelValue{
+								{
+									Value:   "foo",
+									Present: true,
+								}, {
+									Value:   "bar",
+									Present: true,
+								},
+							},
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewInt64Point(endTime1, 123),
+								ocmetricdata.NewInt64Point(endTime2, 1236),
+							},
+						},
+					},
+				}, {
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/gauge-b",
+						Description: "a float testing gauge",
+						Unit:        ocmetricdata.UnitBytes,
+						Type:        ocmetricdata.TypeGaugeFloat64,
+						LabelKeys: []ocmetricdata.LabelKey{
+							{Key: "cf"},
+							{Key: "df"},
+						},
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							LabelValues: []ocmetricdata.LabelValue{
+								{
+									Value:   "foof",
+									Present: true,
+								}, {
+									Value:   "barf",
+									Present: true,
+								},
+							},
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewFloat64Point(endTime1, 123.4),
+								ocmetricdata.NewFloat64Point(endTime2, 1236.7),
+							},
+						},
+					},
+				}, {
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/sum-a",
+						Description: "an int testing sum",
+						Unit:        ocmetricdata.UnitMilliseconds,
+						Type:        ocmetricdata.TypeCumulativeInt64,
+						LabelKeys: []ocmetricdata.LabelKey{
+							{Key: "e"},
+							{Key: "f"},
+						},
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							LabelValues: []ocmetricdata.LabelValue{
+								{
+									Value:   "zig",
+									Present: true,
+								}, {
+									Value:   "zag",
+									Present: true,
+								},
+							},
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewInt64Point(endTime1, 13),
+								ocmetricdata.NewInt64Point(endTime2, 14),
+							},
+						},
+					},
+				}, {
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/sum-b",
+						Description: "a float testing sum",
+						Unit:        ocmetricdata.UnitMilliseconds,
+						Type:        ocmetricdata.TypeCumulativeFloat64,
+						LabelKeys: []ocmetricdata.LabelKey{
+							{Key: "e"},
+							{Key: "f"},
+						},
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							LabelValues: []ocmetricdata.LabelValue{
+								{
+									Value:   "zig",
+									Present: true,
+								}, {
+									Value:   "zag",
+									Present: true,
+								},
+							},
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewFloat64Point(endTime1, 12.3),
+								ocmetricdata.NewFloat64Point(endTime2, 123.4),
+							},
+						},
+					},
+				},
+			},
+			expected: []metricdata.Metrics{
+				{
+					Name:        "foo.com/histogram-a",
+					Description: "a testing histogram",
+					Unit:        "1",
+					Data: metricdata.Histogram[float64]{
+						DataPoints: []metricdata.HistogramDataPoint[float64]{
+							{
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("a"),
+									Value: attribute.StringValue("hello"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("b"),
+									Value: attribute.StringValue("world"),
+								}),
+								StartTime:    startTime,
+								Time:         endTime1,
+								Count:        8,
+								Sum:          100.0,
+								Bounds:       []float64{1.0, 2.0, 3.0},
+								BucketCounts: []uint64{1, 2, 5},
+							}, {
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("a"),
+									Value: attribute.StringValue("hello"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("b"),
+									Value: attribute.StringValue("world"),
+								}),
+								StartTime:    startTime,
+								Time:         endTime2,
+								Count:        10,
+								Sum:          110.0,
+								Bounds:       []float64{1.0, 2.0, 3.0},
+								BucketCounts: []uint64{1, 4, 5},
+							},
+						},
+						Temporality: metricdata.CumulativeTemporality,
+					},
+				}, {
+					Name:        "foo.com/gauge-a",
+					Description: "an int testing gauge",
+					Unit:        "By",
+					Data: metricdata.Gauge[int64]{
+						DataPoints: []metricdata.DataPoint[int64]{
+							{
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("c"),
+									Value: attribute.StringValue("foo"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("d"),
+									Value: attribute.StringValue("bar"),
+								}),
+								Time:  endTime1,
+								Value: 123,
+							}, {
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("c"),
+									Value: attribute.StringValue("foo"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("d"),
+									Value: attribute.StringValue("bar"),
+								}),
+								Time:  endTime2,
+								Value: 1236,
+							},
+						},
+					},
+				}, {
+					Name:        "foo.com/gauge-b",
+					Description: "a float testing gauge",
+					Unit:        "By",
+					Data: metricdata.Gauge[float64]{
+						DataPoints: []metricdata.DataPoint[float64]{
+							{
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("cf"),
+									Value: attribute.StringValue("foof"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("df"),
+									Value: attribute.StringValue("barf"),
+								}),
+								Time:  endTime1,
+								Value: 123.4,
+							}, {
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("cf"),
+									Value: attribute.StringValue("foof"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("df"),
+									Value: attribute.StringValue("barf"),
+								}),
+								Time:  endTime2,
+								Value: 1236.7,
+							},
+						},
+					},
+				}, {
+					Name:        "foo.com/sum-a",
+					Description: "an int testing sum",
+					Unit:        "ms",
+					Data: metricdata.Sum[int64]{
+						IsMonotonic: true,
+						Temporality: metricdata.CumulativeTemporality,
+						DataPoints: []metricdata.DataPoint[int64]{
+							{
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("e"),
+									Value: attribute.StringValue("zig"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("f"),
+									Value: attribute.StringValue("zag"),
+								}),
+								Time:  endTime1,
+								Value: 13,
+							}, {
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("e"),
+									Value: attribute.StringValue("zig"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("f"),
+									Value: attribute.StringValue("zag"),
+								}),
+								Time:  endTime2,
+								Value: 14,
+							},
+						},
+					},
+				}, {
+					Name:        "foo.com/sum-b",
+					Description: "a float testing sum",
+					Unit:        "ms",
+					Data: metricdata.Sum[float64]{
+						IsMonotonic: true,
+						Temporality: metricdata.CumulativeTemporality,
+						DataPoints: []metricdata.DataPoint[float64]{
+							{
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("e"),
+									Value: attribute.StringValue("zig"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("f"),
+									Value: attribute.StringValue("zag"),
+								}),
+								Time:  endTime1,
+								Value: 12.3,
+							}, {
+								Attributes: attribute.NewSet(attribute.KeyValue{
+									Key:   attribute.Key("e"),
+									Value: attribute.StringValue("zig"),
+								}, attribute.KeyValue{
+									Key:   attribute.Key("f"),
+									Value: attribute.StringValue("zag"),
+								}),
+								Time:  endTime2,
+								Value: 123.4,
+							},
+						},
+					},
+				},
+			},
+		}, {
+			desc: "histogram without data points",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/histogram-a",
+						Description: "a testing histogram",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeCumulativeDistribution,
+					},
+				},
+			},
+			expected: []metricdata.Metrics{
+				{
+					Name:        "foo.com/histogram-a",
+					Description: "a testing histogram",
+					Unit:        "1",
+					Data: metricdata.Histogram[float64]{
+						Temporality: metricdata.CumulativeTemporality,
+						DataPoints:  []metricdata.HistogramDataPoint[float64]{},
+					},
+				},
+			},
+		}, {
+			desc: "sum without data points",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/sum-a",
+						Description: "a testing sum",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeCumulativeFloat64,
+					},
+				},
+			},
+			expected: []metricdata.Metrics{
+				{
+					Name:        "foo.com/sum-a",
+					Description: "a testing sum",
+					Unit:        "1",
+					Data: metricdata.Sum[float64]{
+						IsMonotonic: true,
+						Temporality: metricdata.CumulativeTemporality,
+						DataPoints:  []metricdata.DataPoint[float64]{},
+					},
+				},
+			},
+		}, {
+			desc: "gauge without data points",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/gauge-a",
+						Description: "a testing gauge",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeGaugeInt64,
+					},
+				},
+			},
+			expected: []metricdata.Metrics{
+				{
+					Name:        "foo.com/gauge-a",
+					Description: "a testing gauge",
+					Unit:        "1",
+					Data: metricdata.Gauge[int64]{
+						DataPoints: []metricdata.DataPoint[int64]{},
+					},
+				},
+			},
+		}, {
+			desc: "histogram with negative count",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/histogram-a",
+						Description: "a testing histogram",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeCumulativeDistribution,
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewDistributionPoint(endTime1, &ocmetricdata.Distribution{
+									Count: -8,
+								}),
+							},
+							StartTime: startTime,
+						},
+					},
+				},
+			},
+			expectedErr: errConversion,
+		}, {
+			desc: "histogram with negative bucket count",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/histogram-a",
+						Description: "a testing histogram",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeCumulativeDistribution,
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewDistributionPoint(endTime1, &ocmetricdata.Distribution{
+									Buckets: []ocmetricdata.Bucket{
+										{Count: -1},
+										{Count: 2},
+										{Count: 5},
+									},
+								}),
+							},
+							StartTime: startTime,
+						},
+					},
+				},
+			},
+			expectedErr: errConversion,
+		}, {
+			desc: "histogram with non-histogram datapoint type",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/bad-point",
+						Description: "a bad type",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeCumulativeDistribution,
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewFloat64Point(endTime1, 1.0),
+							},
+							StartTime: startTime,
+						},
+					},
+				},
+			},
+			expectedErr: errConversion,
+		}, {
+			desc: "sum with non-sum datapoint type",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/bad-point",
+						Description: "a bad type",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeCumulativeFloat64,
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewDistributionPoint(endTime1, &ocmetricdata.Distribution{}),
+							},
+							StartTime: startTime,
+						},
+					},
+				},
+			},
+			expectedErr: errConversion,
+		}, {
+			desc: "gauge with non-gauge datapoint type",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/bad-point",
+						Description: "a bad type",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeGaugeFloat64,
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							Points: []ocmetricdata.Point{
+								ocmetricdata.NewDistributionPoint(endTime1, &ocmetricdata.Distribution{}),
+							},
+							StartTime: startTime,
+						},
+					},
+				},
+			},
+			expectedErr: errConversion,
+		}, {
+			desc: "unsupported Gauge Distribution type",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/bad-point",
+						Description: "a bad type",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeGaugeDistribution,
+					},
+				},
+			},
+			expectedErr: errConversion,
+		},
+	} {
+		t.Run(tc.desc, func(t *testing.T) {
+			output, err := ConvertMetrics(tc.input)
+			if !errors.Is(err, tc.expectedErr) {
+				t.Errorf("convertAggregation(%+v) = err(%v), want err(%v)", tc.input, err, tc.expectedErr)
+			}
+			metricdatatest.AssertEqual[metricdata.ScopeMetrics](t,
+				metricdata.ScopeMetrics{Metrics: tc.expected},
+				metricdata.ScopeMetrics{Metrics: output})
+		})
+	}
+}
+
+func TestConvertAttributes(t *testing.T) {
+	setWithMultipleKeys := attribute.NewSet(
+		attribute.KeyValue{Key: attribute.Key("first"), Value: attribute.StringValue("1")},
+		attribute.KeyValue{Key: attribute.Key("second"), Value: attribute.StringValue("2")},
+	)
+	for _, tc := range []struct {
+		desc        string
+		inputKeys   []ocmetricdata.LabelKey
+		inputValues []ocmetricdata.LabelValue
+		expected    *attribute.Set
+		expectedErr error
+	}{
+		{
+			desc:     "no attributes",
+			expected: attribute.EmptySet(),
+		},
+		{
+			desc:        "different numbers of keys and values",
+			inputKeys:   []ocmetricdata.LabelKey{{Key: "foo"}},
+			expected:    attribute.EmptySet(),
+			expectedErr: errMismatchedAttributeKeyValues,
+		},
+		{
+			desc:      "multiple keys and values",
+			inputKeys: []ocmetricdata.LabelKey{{Key: "first"}, {Key: "second"}},
+			inputValues: []ocmetricdata.LabelValue{
+				{Value: "1", Present: true},
+				{Value: "2", Present: true},
+			},
+			expected: &setWithMultipleKeys,
+		},
+		{
+			desc:      "multiple keys and values with some not present",
+			inputKeys: []ocmetricdata.LabelKey{{Key: "first"}, {Key: "second"}, {Key: "third"}},
+			inputValues: []ocmetricdata.LabelValue{
+				{Value: "1", Present: true},
+				{Value: "2", Present: true},
+				{Present: false},
+			},
+			expected: &setWithMultipleKeys,
+		},
+	} {
+		t.Run(tc.desc, func(t *testing.T) {
+			output, err := convertAttrs(tc.inputKeys, tc.inputValues)
+			if !errors.Is(err, tc.expectedErr) {
+				t.Errorf("convertAttrs(keys: %v, values: %v) = err(%v), want err(%v)", tc.inputKeys, tc.inputValues, err, tc.expectedErr)
+			}
+			if !output.Equals(tc.expected) {
+				t.Errorf("convertAttrs(keys: %v, values: %v) = %+v, want %+v", tc.inputKeys, tc.inputValues, output.ToSlice(), tc.expected.ToSlice())
+			}
+		})
+	}
+}

+ 34 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc/span_context.go

@@ -0,0 +1,34 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package otel2oc // import "go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc"
+
+import (
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+func SpanContext(sc trace.SpanContext) octrace.SpanContext {
+	var to octrace.TraceOptions
+	if sc.IsSampled() {
+		// OpenCensus doesn't expose functions to directly set sampled
+		to = 0x1
+	}
+	return octrace.SpanContext{
+		TraceID:      octrace.TraceID(sc.TraceID()),
+		SpanID:       octrace.SpanID(sc.SpanID()),
+		TraceOptions: to,
+	}
+}

+ 67 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc/span_context_test.go

@@ -0,0 +1,67 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package otel2oc
+
+import (
+	"testing"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+func TestSpanContextConversion(t *testing.T) {
+	for _, tc := range []struct {
+		description string
+		input       trace.SpanContext
+		expected    octrace.SpanContext
+	}{
+		{
+			description: "empty",
+		},
+		{
+			description: "sampled",
+			input: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    trace.TraceID([16]byte{1}),
+				SpanID:     trace.SpanID([8]byte{2}),
+				TraceFlags: trace.FlagsSampled,
+			}),
+			expected: octrace.SpanContext{
+				TraceID:      octrace.TraceID([16]byte{1}),
+				SpanID:       octrace.SpanID([8]byte{2}),
+				TraceOptions: octrace.TraceOptions(0x1),
+			},
+		},
+		{
+			description: "not sampled",
+			input: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: trace.TraceID([16]byte{1}),
+				SpanID:  trace.SpanID([8]byte{2}),
+			}),
+			expected: octrace.SpanContext{
+				TraceID:      octrace.TraceID([16]byte{1}),
+				SpanID:       octrace.SpanID([8]byte{2}),
+				TraceOptions: octrace.TraceOptions(0),
+			},
+		},
+	} {
+		t.Run(tc.description, func(t *testing.T) {
+			output := SpanContext(tc.input)
+			if output != tc.expected {
+				t.Fatalf("Got %+v spancontext, expected %+v.", output, tc.expected)
+			}
+		})
+	}
+}

+ 131 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/span.go

@@ -0,0 +1,131 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opentelemetry.io/otel/bridge/opencensus/internal"
+
+import (
+	"fmt"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/trace"
+)
+
+const (
+	// MessageSendEvent is the name of the message send event.
+	MessageSendEvent = "message send"
+	// MessageReceiveEvent is the name of the message receive event.
+	MessageReceiveEvent = "message receive"
+)
+
+var (
+	// UncompressedKey is used for the uncompressed byte size attribute.
+	UncompressedKey = attribute.Key("uncompressed byte size")
+	// CompressedKey is used for the compressed byte size attribute.
+	CompressedKey = attribute.Key("compressed byte size")
+)
+
+// Span is an OpenCensus SpanInterface wrapper for an OpenTelemetry Span.
+type Span struct {
+	otelSpan trace.Span
+}
+
+// NewSpan returns an OpenCensus Span wrapping an OpenTelemetry Span.
+func NewSpan(s trace.Span) *octrace.Span {
+	return octrace.NewSpan(&Span{otelSpan: s})
+}
+
+// IsRecordingEvents returns true if events are being recorded for this span.
+func (s *Span) IsRecordingEvents() bool {
+	return s.otelSpan.IsRecording()
+}
+
+// End ends this span.
+func (s *Span) End() {
+	s.otelSpan.End()
+}
+
+// SpanContext returns the SpanContext of this span.
+func (s *Span) SpanContext() octrace.SpanContext {
+	return otel2oc.SpanContext(s.otelSpan.SpanContext())
+}
+
+// SetName sets the name of this span, if it is recording events.
+func (s *Span) SetName(name string) {
+	s.otelSpan.SetName(name)
+}
+
+// SetStatus sets the status of this span, if it is recording events.
+func (s *Span) SetStatus(status octrace.Status) {
+	s.otelSpan.SetStatus(codes.Code(status.Code), status.Message)
+}
+
+// AddAttributes sets attributes in this span.
+func (s *Span) AddAttributes(attributes ...octrace.Attribute) {
+	s.otelSpan.SetAttributes(oc2otel.Attributes(attributes)...)
+}
+
+// Annotate adds an annotation with attributes to this span.
+func (s *Span) Annotate(attributes []octrace.Attribute, str string) {
+	s.otelSpan.AddEvent(str, trace.WithAttributes(oc2otel.Attributes(attributes)...))
+}
+
+// Annotatef adds a formatted annotation with attributes to this span.
+func (s *Span) Annotatef(attributes []octrace.Attribute, format string, a ...interface{}) {
+	s.Annotate(attributes, fmt.Sprintf(format, a...))
+}
+
+// AddMessageSendEvent adds a message send event to this span.
+func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+	s.otelSpan.AddEvent(MessageSendEvent,
+		trace.WithAttributes(
+			attribute.KeyValue{
+				Key:   UncompressedKey,
+				Value: attribute.Int64Value(uncompressedByteSize),
+			},
+			attribute.KeyValue{
+				Key:   CompressedKey,
+				Value: attribute.Int64Value(compressedByteSize),
+			}),
+	)
+}
+
+// AddMessageReceiveEvent adds a message receive event to this span.
+func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+	s.otelSpan.AddEvent(MessageReceiveEvent,
+		trace.WithAttributes(
+			attribute.KeyValue{
+				Key:   UncompressedKey,
+				Value: attribute.Int64Value(uncompressedByteSize),
+			},
+			attribute.KeyValue{
+				Key:   CompressedKey,
+				Value: attribute.Int64Value(compressedByteSize),
+			}),
+	)
+}
+
+// AddLink adds a link to this span.
+func (s *Span) AddLink(l octrace.Link) {
+	Handle(fmt.Errorf("ignoring OpenCensus link %+v for span %q because OpenTelemetry doesn't support setting links after creation", l, s.String()))
+}
+
+// String prints a string representation of this span.
+func (s *Span) String() string {
+	return fmt.Sprintf("span %s", s.otelSpan.SpanContext().SpanID().String())
+}

+ 268 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/span_test.go

@@ -0,0 +1,268 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal_test
+
+import (
+	"testing"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/trace"
+)
+
+type span struct {
+	trace.Span
+
+	recording bool
+	ended     bool
+	sc        trace.SpanContext
+	name      string
+	sCode     codes.Code
+	sMsg      string
+	attrs     []attribute.KeyValue
+	eName     string
+	eOpts     []trace.EventOption
+}
+
+func (s *span) IsRecording() bool                         { return s.recording }
+func (s *span) End(...trace.SpanEndOption)                { s.ended = true }
+func (s *span) SpanContext() trace.SpanContext            { return s.sc }
+func (s *span) SetName(n string)                          { s.name = n }
+func (s *span) SetStatus(c codes.Code, d string)          { s.sCode, s.sMsg = c, d }
+func (s *span) SetAttributes(a ...attribute.KeyValue)     { s.attrs = a }
+func (s *span) AddEvent(n string, o ...trace.EventOption) { s.eName, s.eOpts = n, o }
+
+func TestSpanIsRecordingEvents(t *testing.T) {
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	if !ocS.IsRecordingEvents() {
+		t.Errorf("span.IsRecordingEvents() = false, want true")
+	}
+	s.recording = false
+	if ocS.IsRecordingEvents() {
+		t.Errorf("span.IsRecordingEvents() = true, want false")
+	}
+}
+
+func TestSpanEnd(t *testing.T) {
+	s := new(span)
+	ocS := internal.NewSpan(s)
+	if s.ended {
+		t.Fatal("new span already ended")
+	}
+
+	ocS.End()
+	if !s.ended {
+		t.Error("span.End() did not end OpenTelemetry span")
+	}
+}
+
+func TestSpanSpanContext(t *testing.T) {
+	sc := trace.NewSpanContext(trace.SpanContextConfig{
+		TraceID: [16]byte{1},
+		SpanID:  [8]byte{1},
+	})
+	// Do not test the conversion, only that the method is called.
+	converted := otel2oc.SpanContext(sc)
+
+	s := &span{sc: sc}
+	ocS := internal.NewSpan(s)
+	if ocS.SpanContext() != converted {
+		t.Error("span.SpanContext did not use OpenTelemetry SpanContext")
+	}
+}
+
+func TestSpanSetName(t *testing.T) {
+	// OpenCensus does not set a name if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	name := "test name"
+	ocS.SetName(name)
+	if s.name != name {
+		t.Error("span.SetName did not set OpenTelemetry span name")
+	}
+}
+
+func TestSpanSetStatus(t *testing.T) {
+	// OpenCensus does not set a status if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+
+	c, d := codes.Error, "error"
+	status := octrace.Status{Code: int32(c), Message: d}
+	ocS.SetStatus(status)
+
+	if s.sCode != c {
+		t.Error("span.SetStatus failed to set OpenTelemetry status code")
+	}
+	if s.sMsg != d {
+		t.Error("span.SetStatus failed to set OpenTelemetry status description")
+	}
+}
+
+func TestSpanAddAttributes(t *testing.T) {
+	attrs := []octrace.Attribute{
+		octrace.BoolAttribute("a", true),
+	}
+	// Do not test the conversion, only that the method is called.
+	converted := oc2otel.Attributes(attrs)
+
+	// OpenCensus does not set attributes if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	ocS.AddAttributes(attrs...)
+
+	if len(s.attrs) != len(converted) || s.attrs[0] != converted[0] {
+		t.Error("span.AddAttributes failed to set OpenTelemetry attributes")
+	}
+}
+
+func TestSpanAnnotate(t *testing.T) {
+	name := "annotation"
+	attrs := []octrace.Attribute{
+		octrace.BoolAttribute("a", true),
+	}
+	// Do not test the conversion, only that the method is called.
+	want := oc2otel.Attributes(attrs)
+
+	// OpenCensus does not set events if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	ocS.Annotate(attrs, name)
+
+	if s.eName != name {
+		t.Error("span.Annotate did not set event name")
+	}
+
+	config := trace.NewEventConfig(s.eOpts...)
+	got := config.Attributes()
+	if len(want) != len(got) || want[0] != got[0] {
+		t.Error("span.Annotate did not set event options")
+	}
+}
+
+func TestSpanAnnotatef(t *testing.T) {
+	format := "annotation %s"
+	attrs := []octrace.Attribute{
+		octrace.BoolAttribute("a", true),
+	}
+	// Do not test the conversion, only that the method is called.
+	want := oc2otel.Attributes(attrs)
+
+	// OpenCensus does not set events if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	ocS.Annotatef(attrs, format, "a")
+
+	if s.eName != "annotation a" {
+		t.Error("span.Annotatef did not set event name")
+	}
+
+	config := trace.NewEventConfig(s.eOpts...)
+	got := config.Attributes()
+	if len(want) != len(got) || want[0] != got[0] {
+		t.Error("span.Annotatef did not set event options")
+	}
+}
+
+func TestSpanAddMessageSendEvent(t *testing.T) {
+	var u, c int64 = 1, 2
+
+	// OpenCensus does not set events if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	ocS.AddMessageSendEvent(0, u, c)
+
+	if s.eName != internal.MessageSendEvent {
+		t.Error("span.AddMessageSendEvent did not set event name")
+	}
+
+	config := trace.NewEventConfig(s.eOpts...)
+	got := config.Attributes()
+	if len(got) != 2 {
+		t.Fatalf("span.AddMessageSendEvent set %d attributes, want 2", len(got))
+	}
+
+	want := attribute.KeyValue{Key: internal.UncompressedKey, Value: attribute.Int64Value(u)}
+	if got[0] != want {
+		t.Errorf("span.AddMessageSendEvent wrong uncompressed attribute: %v", got[0])
+	}
+
+	want = attribute.KeyValue{Key: internal.CompressedKey, Value: attribute.Int64Value(c)}
+	if got[1] != want {
+		t.Errorf("span.AddMessageSendEvent wrong compressed attribute: %v", got[1])
+	}
+}
+
+func TestSpanAddMessageReceiveEvent(t *testing.T) {
+	var u, c int64 = 3, 4
+
+	// OpenCensus does not set events if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	ocS.AddMessageReceiveEvent(0, u, c)
+
+	if s.eName != internal.MessageReceiveEvent {
+		t.Error("span.AddMessageReceiveEvent did not set event name")
+	}
+
+	config := trace.NewEventConfig(s.eOpts...)
+	got := config.Attributes()
+	if len(got) != 2 {
+		t.Fatalf("span.AddMessageReceiveEvent set %d attributes, want 2", len(got))
+	}
+
+	want := attribute.KeyValue{Key: internal.UncompressedKey, Value: attribute.Int64Value(u)}
+	if got[0] != want {
+		t.Errorf("span.AddMessageReceiveEvent wrong uncompressed attribute: %v", got[0])
+	}
+
+	want = attribute.KeyValue{Key: internal.CompressedKey, Value: attribute.Int64Value(c)}
+	if got[1] != want {
+		t.Errorf("span.AddMessageReceiveEvent wrong compressed attribute: %v", got[1])
+	}
+}
+
+func TestSpanAddLinkFails(t *testing.T) {
+	h, restore := withHandler()
+	defer restore()
+
+	// OpenCensus does not try to set links if not recording.
+	s := &span{recording: true}
+	ocS := internal.NewSpan(s)
+	ocS.AddLink(octrace.Link{})
+
+	if h.err == nil {
+		t.Error("span.AddLink failed to raise an error")
+	}
+}
+
+func TestSpanString(t *testing.T) {
+	sc := trace.NewSpanContext(trace.SpanContextConfig{
+		TraceID: [16]byte{1},
+		SpanID:  [8]byte{1},
+	})
+
+	s := &span{sc: sc}
+	ocS := internal.NewSpan(s)
+	if expected := "span 0100000000000000"; ocS.String() != expected {
+		t.Errorf("span.String = %q, not %q", ocS.String(), expected)
+	}
+}

+ 69 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/tracer.go

@@ -0,0 +1,69 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opentelemetry.io/otel/bridge/opencensus/internal"
+
+import (
+	"context"
+	"fmt"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// Tracer is an OpenCensus Tracer that wraps an OpenTelemetry Tracer.
+type Tracer struct {
+	otelTracer trace.Tracer
+}
+
+// NewTracer returns an OpenCensus Tracer that wraps the OpenTelemetry tracer.
+func NewTracer(tracer trace.Tracer) octrace.Tracer {
+	return &Tracer{otelTracer: tracer}
+}
+
+// StartSpan starts a new child span of the current span in the context. If
+// there is no span in the context, it creates a new trace and span.
+func (o *Tracer) StartSpan(ctx context.Context, name string, s ...octrace.StartOption) (context.Context, *octrace.Span) {
+	otelOpts, err := oc2otel.StartOptions(s)
+	if err != nil {
+		Handle(fmt.Errorf("starting span %q: %w", name, err))
+	}
+	ctx, sp := o.otelTracer.Start(ctx, name, otelOpts...)
+	return ctx, NewSpan(sp)
+}
+
+// StartSpanWithRemoteParent starts a new child span of the span from the
+// given parent.
+func (o *Tracer) StartSpanWithRemoteParent(ctx context.Context, name string, parent octrace.SpanContext, s ...octrace.StartOption) (context.Context, *octrace.Span) {
+	// make sure span context is zero'd out so we use the remote parent
+	ctx = trace.ContextWithSpan(ctx, nil)
+	ctx = trace.ContextWithRemoteSpanContext(ctx, oc2otel.SpanContext(parent))
+	return o.StartSpan(ctx, name, s...)
+}
+
+// FromContext returns the Span stored in a context.
+func (o *Tracer) FromContext(ctx context.Context) *octrace.Span {
+	return NewSpan(trace.SpanFromContext(ctx))
+}
+
+// NewContext returns a new context with the given Span attached.
+func (o *Tracer) NewContext(parent context.Context, s *octrace.Span) context.Context {
+	if otSpan, ok := s.Internal().(*Span); ok {
+		return trace.ContextWithSpan(parent, otSpan.otelSpan)
+	}
+	Handle(fmt.Errorf("unable to create context with span %q, since it was created using a different tracer", s.String()))
+	return parent
+}

+ 161 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/internal/tracer_test.go

@@ -0,0 +1,161 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal_test
+
+import (
+	"context"
+	"testing"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/bridge/opencensus/internal"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc"
+	"go.opentelemetry.io/otel/trace"
+)
+
+type handler struct{ err error }
+
+func (h *handler) Handle(e error) { h.err = e }
+
+func withHandler() (*handler, func()) {
+	h := new(handler)
+	original := internal.Handle
+	internal.Handle = h.Handle
+	return h, func() { internal.Handle = original }
+}
+
+type tracer struct {
+	ctx  context.Context
+	name string
+	opts []trace.SpanStartOption
+}
+
+func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
+	t.ctx, t.name, t.opts = ctx, name, opts
+	noop := trace.NewNoopTracerProvider().Tracer("testing")
+	return noop.Start(ctx, name, opts...)
+}
+
+type ctxKey string
+
+func TestTracerStartSpan(t *testing.T) {
+	h, restore := withHandler()
+	defer restore()
+
+	otelTracer := &tracer{}
+	ocTracer := internal.NewTracer(otelTracer)
+
+	ctx := context.WithValue(context.Background(), ctxKey("key"), "value")
+	name := "testing span"
+	ocTracer.StartSpan(ctx, name, octrace.WithSpanKind(octrace.SpanKindClient))
+	if h.err != nil {
+		t.Fatalf("OC tracer.StartSpan errored: %v", h.err)
+	}
+
+	if otelTracer.ctx != ctx {
+		t.Error("OTel tracer.Start called with wrong context")
+	}
+	if otelTracer.name != name {
+		t.Error("OTel tracer.Start called with wrong name")
+	}
+	sk := trace.SpanKindClient
+	c := trace.NewSpanStartConfig(otelTracer.opts...)
+	if c.SpanKind() != sk {
+		t.Errorf("OTel tracer.Start called with wrong options: %#v", c)
+	}
+}
+
+func TestTracerStartSpanReportsErrors(t *testing.T) {
+	h, restore := withHandler()
+	defer restore()
+
+	ocTracer := internal.NewTracer(&tracer{})
+	ocTracer.StartSpan(context.Background(), "", octrace.WithSampler(octrace.AlwaysSample()))
+	if h.err == nil {
+		t.Error("OC tracer.StartSpan no error when converting Sampler")
+	}
+}
+
+func TestTracerStartSpanWithRemoteParent(t *testing.T) {
+	otelTracer := new(tracer)
+	ocTracer := internal.NewTracer(otelTracer)
+	sc := octrace.SpanContext{TraceID: [16]byte{1}, SpanID: [8]byte{1}}
+	converted := oc2otel.SpanContext(sc).WithRemote(true)
+
+	ocTracer.StartSpanWithRemoteParent(context.Background(), "", sc)
+
+	got := trace.SpanContextFromContext(otelTracer.ctx)
+	if !got.Equal(converted) {
+		t.Error("tracer.StartSpanWithRemoteParent failed to set remote parent")
+	}
+}
+
+func TestTracerFromContext(t *testing.T) {
+	sc := trace.NewSpanContext(trace.SpanContextConfig{
+		TraceID: [16]byte{1},
+		SpanID:  [8]byte{1},
+	})
+	ctx := trace.ContextWithSpanContext(context.Background(), sc)
+
+	noop := trace.NewNoopTracerProvider().Tracer("TestTracerFromContext")
+	// Test using the fact that the No-Op span will propagate a span context .
+	ctx, _ = noop.Start(ctx, "test")
+
+	got := internal.NewTracer(noop).FromContext(ctx).SpanContext()
+	// Do not test the convedsion, only that the propagtion.
+	want := otel2oc.SpanContext(sc)
+	if got != want {
+		t.Errorf("tracer.FromContext returned wrong context: %#v", got)
+	}
+}
+
+func TestTracerNewContext(t *testing.T) {
+	sc := trace.NewSpanContext(trace.SpanContextConfig{
+		TraceID: [16]byte{1},
+		SpanID:  [8]byte{1},
+	})
+	ctx := trace.ContextWithSpanContext(context.Background(), sc)
+
+	noop := trace.NewNoopTracerProvider().Tracer("TestTracerNewContext")
+	// Test using the fact that the No-Op span will propagate a span context .
+	_, s := noop.Start(ctx, "test")
+
+	ocTracer := internal.NewTracer(noop)
+	ctx = ocTracer.NewContext(context.Background(), internal.NewSpan(s))
+	got := trace.SpanContextFromContext(ctx)
+
+	if !got.Equal(sc) {
+		t.Error("tracer.NewContext did not attach Span to context")
+	}
+}
+
+type differentSpan struct {
+	octrace.SpanInterface
+}
+
+func (s *differentSpan) String() string { return "testing span" }
+
+func TestTracerNewContextErrors(t *testing.T) {
+	h, restore := withHandler()
+	defer restore()
+
+	ocTracer := internal.NewTracer(&tracer{})
+	ocSpan := octrace.NewSpan(&differentSpan{})
+	ocTracer.NewContext(context.Background(), ocSpan)
+	if h.err == nil {
+		t.Error("tracer.NewContext did not error for unrecognized span")
+	}
+}

+ 59 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/metric.go

@@ -0,0 +1,59 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opencensus // import "go.opentelemetry.io/otel/bridge/opencensus"
+
+import (
+	"context"
+
+	ocmetricdata "go.opencensus.io/metric/metricdata"
+	"go.opencensus.io/metric/metricproducer"
+
+	internal "go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	"go.opentelemetry.io/otel/sdk/metric"
+	"go.opentelemetry.io/otel/sdk/metric/metricdata"
+)
+
+const scopeName = "go.opentelemetry.io/otel/bridge/opencensus"
+
+type producer struct {
+	manager *metricproducer.Manager
+}
+
+// NewMetricProducer returns a metric.Producer that fetches metrics from
+// OpenCensus.
+func NewMetricProducer() metric.Producer {
+	return &producer{
+		manager: metricproducer.GlobalManager(),
+	}
+}
+
+func (p *producer) Produce(context.Context) ([]metricdata.ScopeMetrics, error) {
+	producers := p.manager.GetAll()
+	data := []*ocmetricdata.Metric{}
+	for _, ocProducer := range producers {
+		data = append(data, ocProducer.Read()...)
+	}
+	otelmetrics, err := internal.ConvertMetrics(data)
+	if len(otelmetrics) == 0 {
+		return nil, err
+	}
+	return []metricdata.ScopeMetrics{{
+		Scope: instrumentation.Scope{
+			Name: scopeName,
+		},
+		Metrics: otelmetrics,
+	}}, err
+}

+ 159 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/metric_test.go

@@ -0,0 +1,159 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opencensus // import "go.opentelemetry.io/otel/bridge/opencensus"
+
+import (
+	"context"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
+	ocmetricdata "go.opencensus.io/metric/metricdata"
+	"go.opencensus.io/metric/metricproducer"
+	ocresource "go.opencensus.io/resource"
+
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	"go.opentelemetry.io/otel/sdk/metric/metricdata"
+	"go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest"
+)
+
+func TestMetricProducer(t *testing.T) {
+	now := time.Now()
+	for _, tc := range []struct {
+		desc      string
+		input     []*ocmetricdata.Metric
+		expected  []metricdata.ScopeMetrics
+		expectErr bool
+	}{
+		{
+			desc:     "empty",
+			expected: nil,
+		},
+		{
+			desc: "success",
+			input: []*ocmetricdata.Metric{
+				{
+					Resource: &ocresource.Resource{
+						Labels: map[string]string{
+							"R1": "V1",
+							"R2": "V2",
+						},
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							StartTime: now,
+							Points: []ocmetricdata.Point{
+								{Value: int64(123), Time: now},
+							},
+						},
+					},
+				},
+			},
+			expected: []metricdata.ScopeMetrics{{
+				Scope: instrumentation.Scope{
+					Name: scopeName,
+				},
+				Metrics: []metricdata.Metrics{
+					{
+						Data: metricdata.Gauge[int64]{
+							DataPoints: []metricdata.DataPoint[int64]{
+								{
+									Attributes: attribute.NewSet(),
+									StartTime:  now,
+									Time:       now,
+									Value:      123,
+								},
+							},
+						},
+					},
+				},
+			}},
+		},
+		{
+			desc: "partial success",
+			input: []*ocmetricdata.Metric{
+				{
+					Descriptor: ocmetricdata.Descriptor{
+						Name:        "foo.com/bad-point",
+						Description: "a bad type",
+						Unit:        ocmetricdata.UnitDimensionless,
+						Type:        ocmetricdata.TypeGaugeDistribution,
+					},
+				},
+				{
+					Resource: &ocresource.Resource{
+						Labels: map[string]string{
+							"R1": "V1",
+							"R2": "V2",
+						},
+					},
+					TimeSeries: []*ocmetricdata.TimeSeries{
+						{
+							StartTime: now,
+							Points: []ocmetricdata.Point{
+								{Value: int64(123), Time: now},
+							},
+						},
+					},
+				},
+			},
+			expected: []metricdata.ScopeMetrics{{
+				Scope: instrumentation.Scope{
+					Name: scopeName,
+				},
+				Metrics: []metricdata.Metrics{
+					{
+						Data: metricdata.Gauge[int64]{
+							DataPoints: []metricdata.DataPoint[int64]{
+								{
+									Attributes: attribute.NewSet(),
+									StartTime:  now,
+									Time:       now,
+									Value:      123,
+								},
+							},
+						},
+					},
+				},
+			}},
+			expectErr: true,
+		},
+	} {
+		t.Run(tc.desc, func(t *testing.T) {
+			fakeProducer := &fakeOCProducer{metrics: tc.input}
+			metricproducer.GlobalManager().AddProducer(fakeProducer)
+			defer metricproducer.GlobalManager().DeleteProducer(fakeProducer)
+			output, err := NewMetricProducer().Produce(context.Background())
+			if tc.expectErr {
+				require.Error(t, err)
+			} else {
+				require.Nil(t, err)
+			}
+			require.Equal(t, len(output), len(tc.expected))
+			for i := range output {
+				metricdatatest.AssertEqual(t, tc.expected[i], output[i])
+			}
+		})
+	}
+}
+
+type fakeOCProducer struct {
+	metrics []*ocmetricdata.Metric
+}
+
+func (f *fakeOCProducer) Read() []*ocmetricdata.Metric {
+	return f.metrics
+}

+ 289 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/test/bridge_test.go

@@ -0,0 +1,289 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package test
+
+import (
+	"context"
+	"testing"
+
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/attribute"
+	ocbridge "go.opentelemetry.io/otel/bridge/opencensus"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal"
+	"go.opentelemetry.io/otel/codes"
+	sdktrace "go.opentelemetry.io/otel/sdk/trace"
+	"go.opentelemetry.io/otel/sdk/trace/tracetest"
+	"go.opentelemetry.io/otel/trace"
+)
+
+func TestMixedAPIs(t *testing.T) {
+	sr := tracetest.NewSpanRecorder()
+	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
+	tracer := tp.Tracer("mixedapitracer")
+	octrace.DefaultTracer = ocbridge.NewTracer(tracer)
+
+	func() {
+		ctx := context.Background()
+		var ocspan1 *octrace.Span
+		ctx, ocspan1 = octrace.StartSpan(ctx, "OpenCensusSpan1")
+		defer ocspan1.End()
+
+		var otspan1 trace.Span
+		ctx, otspan1 = tracer.Start(ctx, "OpenTelemetrySpan1")
+		defer otspan1.End()
+
+		var ocspan2 *octrace.Span
+		ctx, ocspan2 = octrace.StartSpan(ctx, "OpenCensusSpan2")
+		defer ocspan2.End()
+
+		var otspan2 trace.Span
+		_, otspan2 = tracer.Start(ctx, "OpenTelemetrySpan2")
+		defer otspan2.End()
+	}()
+
+	spans := sr.Ended()
+
+	if len(spans) != 4 {
+		for _, span := range spans {
+			t.Logf("Span: %s", span.Name())
+		}
+		t.Fatalf("Got %d spans, expected %d.", len(spans), 4)
+	}
+
+	var parent trace.SpanContext
+	for i := len(spans) - 1; i >= 0; i-- {
+		// Verify that OpenCensus spans and OpenTelemetry spans have each
+		// other as parents.
+		if psid := spans[i].Parent().SpanID(); psid != parent.SpanID() {
+			t.Errorf("Span %v had parent %v. Expected %v", spans[i].Name(), psid, parent.SpanID())
+		}
+		parent = spans[i].SpanContext()
+	}
+}
+
+func TestStartOptions(t *testing.T) {
+	sr := tracetest.NewSpanRecorder()
+	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
+	octrace.DefaultTracer = ocbridge.NewTracer(tp.Tracer("startoptionstracer"))
+
+	ctx := context.Background()
+	_, span := octrace.StartSpan(ctx, "OpenCensusSpan", octrace.WithSpanKind(octrace.SpanKindClient))
+	span.End()
+
+	spans := sr.Ended()
+
+	if len(spans) != 1 {
+		t.Fatalf("Got %d spans, expected %d", len(spans), 1)
+	}
+
+	if spans[0].SpanKind() != trace.SpanKindClient {
+		t.Errorf("Got span kind %v, expected %d", spans[0].SpanKind(), trace.SpanKindClient)
+	}
+}
+
+func TestStartSpanWithRemoteParent(t *testing.T) {
+	sr := tracetest.NewSpanRecorder()
+	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
+	tracer := tp.Tracer("remoteparent")
+	octrace.DefaultTracer = ocbridge.NewTracer(tracer)
+
+	ctx := context.Background()
+	ctx, parent := tracer.Start(ctx, "OpenTelemetrySpan1")
+
+	_, span := octrace.StartSpanWithRemoteParent(ctx, "OpenCensusSpan", ocbridge.OTelSpanContextToOC(parent.SpanContext()))
+	span.End()
+
+	spans := sr.Ended()
+
+	if len(spans) != 1 {
+		t.Fatalf("Got %d spans, expected %d", len(spans), 1)
+	}
+
+	if psid := spans[0].Parent().SpanID(); psid != parent.SpanContext().SpanID() {
+		t.Errorf("Span %v, had parent %v.  Expected %d", spans[0].Name(), psid, parent.SpanContext().SpanID())
+	}
+}
+
+func TestToFromContext(t *testing.T) {
+	sr := tracetest.NewSpanRecorder()
+	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
+	tracer := tp.Tracer("tofromcontext")
+	octrace.DefaultTracer = ocbridge.NewTracer(tracer)
+
+	func() {
+		ctx := context.Background()
+
+		_, otSpan1 := tracer.Start(ctx, "OpenTelemetrySpan1")
+		defer otSpan1.End()
+
+		// Use NewContext instead of the context from Start
+		ctx = octrace.NewContext(ctx, internal.NewSpan(otSpan1))
+
+		ctx, _ = tracer.Start(ctx, "OpenTelemetrySpan2")
+
+		// Get the opentelemetry span using the OpenCensus FromContext, and end it
+		otSpan2 := octrace.FromContext(ctx)
+		defer otSpan2.End()
+	}()
+
+	spans := sr.Ended()
+
+	if len(spans) != 2 {
+		t.Fatalf("Got %d spans, expected %d.", len(spans), 2)
+	}
+
+	var parent trace.SpanContext
+	for i := len(spans) - 1; i >= 0; i-- {
+		// Verify that OpenCensus spans and OpenTelemetry spans have each
+		// other as parents.
+		if psid := spans[i].Parent().SpanID(); psid != parent.SpanID() {
+			t.Errorf("Span %v had parent %v. Expected %v", spans[i].Name(), psid, parent.SpanID())
+		}
+		parent = spans[i].SpanContext()
+	}
+}
+
+func TestIsRecordingEvents(t *testing.T) {
+	sr := tracetest.NewSpanRecorder()
+	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
+	octrace.DefaultTracer = ocbridge.NewTracer(tp.Tracer("isrecordingevents"))
+
+	ctx := context.Background()
+	_, ocspan := octrace.StartSpan(ctx, "OpenCensusSpan1")
+	if !ocspan.IsRecordingEvents() {
+		t.Errorf("Got %v, expected true", ocspan.IsRecordingEvents())
+	}
+}
+
+func attrsMap(s []attribute.KeyValue) map[attribute.Key]attribute.Value {
+	m := make(map[attribute.Key]attribute.Value, len(s))
+	for _, a := range s {
+		m[a.Key] = a.Value
+	}
+	return m
+}
+
+func TestSetThings(t *testing.T) {
+	sr := tracetest.NewSpanRecorder()
+	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
+	octrace.DefaultTracer = ocbridge.NewTracer(tp.Tracer("setthings"))
+
+	ctx := context.Background()
+	_, ocspan := octrace.StartSpan(ctx, "OpenCensusSpan1")
+	ocspan.SetName("span-foo")
+	ocspan.SetStatus(octrace.Status{Code: 1, Message: "foo"})
+	ocspan.AddAttributes(
+		octrace.BoolAttribute("bool", true),
+		octrace.Int64Attribute("int64", 12345),
+		octrace.Float64Attribute("float64", 12.345),
+		octrace.StringAttribute("string", "stringval"),
+	)
+	ocspan.Annotate(
+		[]octrace.Attribute{octrace.StringAttribute("string", "annotateval")},
+		"annotate",
+	)
+	ocspan.Annotatef(
+		[]octrace.Attribute{
+			octrace.Int64Attribute("int64", 12345),
+			octrace.Float64Attribute("float64", 12.345),
+		},
+		"annotate%d", 67890,
+	)
+	ocspan.AddMessageSendEvent(123, 456, 789)
+	ocspan.AddMessageReceiveEvent(246, 135, 369)
+	ocspan.End()
+
+	spans := sr.Ended()
+
+	if len(spans) != 1 {
+		t.Fatalf("Got %d spans, expected %d.", len(spans), 1)
+	}
+	s := spans[0]
+
+	if s.Name() != "span-foo" {
+		t.Errorf("Got name %v, expected span-foo", s.Name())
+	}
+
+	if s.Status().Code != codes.Error {
+		t.Errorf("Got code %v, expected %v", s.Status().Code, codes.Error)
+	}
+
+	if s.Status().Description != "foo" {
+		t.Errorf("Got code %v, expected foo", s.Status().Description)
+	}
+
+	attrs := attrsMap(s.Attributes())
+	if v := attrs[attribute.Key("bool")]; !v.AsBool() {
+		t.Errorf("Got attributes[bool] %v, expected true", v.AsBool())
+	}
+	if v := attrs[attribute.Key("int64")]; v.AsInt64() != 12345 {
+		t.Errorf("Got attributes[int64] %v, expected 12345", v.AsInt64())
+	}
+	if v := attrs[attribute.Key("float64")]; v.AsFloat64() != 12.345 {
+		t.Errorf("Got attributes[float64] %v, expected 12.345", v.AsFloat64())
+	}
+	if v := attrs[attribute.Key("string")]; v.AsString() != "stringval" {
+		t.Errorf("Got attributes[string] %v, expected stringval", v.AsString())
+	}
+
+	if len(s.Events()) != 4 {
+		t.Fatalf("Got len(events) = %v, expected 4", len(s.Events()))
+	}
+	annotateEvent := s.Events()[0]
+	aeAttrs := attrsMap(annotateEvent.Attributes)
+	annotatefEvent := s.Events()[1]
+	afeAttrs := attrsMap(annotatefEvent.Attributes)
+	sendEvent := s.Events()[2]
+	receiveEvent := s.Events()[3]
+	if v := aeAttrs[attribute.Key("string")]; v.AsString() != "annotateval" {
+		t.Errorf("Got annotateEvent.Attributes[string] = %v, expected annotateval", v.AsString())
+	}
+	if annotateEvent.Name != "annotate" {
+		t.Errorf("Got annotateEvent.Name = %v, expected annotate", annotateEvent.Name)
+	}
+	if v := afeAttrs[attribute.Key("int64")]; v.AsInt64() != 12345 {
+		t.Errorf("Got annotatefEvent.Attributes[int64] = %v, expected 12345", v.AsInt64())
+	}
+	if v := afeAttrs[attribute.Key("float64")]; v.AsFloat64() != 12.345 {
+		t.Errorf("Got annotatefEvent.Attributes[float64] = %v, expected 12.345", v.AsFloat64())
+	}
+	if annotatefEvent.Name != "annotate67890" {
+		t.Errorf("Got annotatefEvent.Name = %v, expected annotate67890", annotatefEvent.Name)
+	}
+	if v := aeAttrs[attribute.Key("string")]; v.AsString() != "annotateval" {
+		t.Errorf("Got annotateEvent.Attributes[string] = %v, expected annotateval", v.AsString())
+	}
+	seAttrs := attrsMap(sendEvent.Attributes)
+	reAttrs := attrsMap(receiveEvent.Attributes)
+	if sendEvent.Name != internal.MessageSendEvent {
+		t.Errorf("Got sendEvent.Name = %v, expected message send", sendEvent.Name)
+	}
+	if v := seAttrs[internal.UncompressedKey]; v.AsInt64() != 456 {
+		t.Errorf("Got sendEvent.Attributes[uncompressedKey] = %v, expected 456", v.AsInt64())
+	}
+	if v := seAttrs[internal.CompressedKey]; v.AsInt64() != 789 {
+		t.Errorf("Got sendEvent.Attributes[compressedKey] = %v, expected 789", v.AsInt64())
+	}
+	if receiveEvent.Name != internal.MessageReceiveEvent {
+		t.Errorf("Got receiveEvent.Name = %v, expected message receive", receiveEvent.Name)
+	}
+	if v := reAttrs[internal.UncompressedKey]; v.AsInt64() != 135 {
+		t.Errorf("Got receiveEvent.Attributes[uncompressedKey] = %v, expected 135", v.AsInt64())
+	}
+	if v := reAttrs[internal.CompressedKey]; v.AsInt64() != 369 {
+		t.Errorf("Got receiveEvent.Attributes[compressedKey] = %v, expected 369", v.AsInt64())
+	}
+}

+ 32 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/test/go.mod

@@ -0,0 +1,32 @@
+module go.opentelemetry.io/otel/bridge/opencensus/test
+
+go 1.20
+
+require (
+	go.opencensus.io v0.24.0
+	go.opentelemetry.io/otel v1.19.0
+	go.opentelemetry.io/otel/bridge/opencensus v0.42.0
+	go.opentelemetry.io/otel/sdk v1.19.0
+	go.opentelemetry.io/otel/trace v1.19.0
+)
+
+require (
+	github.com/go-logr/logr v1.2.4 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
+	go.opentelemetry.io/otel/metric v1.19.0 // indirect
+	go.opentelemetry.io/otel/sdk/metric v1.19.0 // indirect
+	golang.org/x/sys v0.12.0 // indirect
+)
+
+replace go.opentelemetry.io/otel => ../../..
+
+replace go.opentelemetry.io/otel/bridge/opencensus => ../
+
+replace go.opentelemetry.io/otel/sdk => ../../../sdk
+
+replace go.opentelemetry.io/otel/trace => ../../../trace
+
+replace go.opentelemetry.io/otel/metric => ../../../metric
+
+replace go.opentelemetry.io/otel/sdk/metric => ../../../sdk/metric

+ 105 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/test/go.sum

@@ -0,0 +1,105 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 44 - 0
pkg/go.opentelemetry.io/otel/bridge/opencensus/trace.go

@@ -0,0 +1,44 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opencensus // import "go.opentelemetry.io/otel/bridge/opencensus"
+
+import (
+	octrace "go.opencensus.io/trace"
+
+	"go.opentelemetry.io/otel/bridge/opencensus/internal"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
+	"go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// NewTracer returns an implementation of the OpenCensus Tracer interface which
+// uses OpenTelemetry APIs.  Using this implementation of Tracer "upgrades"
+// libraries that use OpenCensus to OpenTelemetry to facilitate a migration.
+func NewTracer(tracer trace.Tracer) octrace.Tracer {
+	return internal.NewTracer(tracer)
+}
+
+// OTelSpanContextToOC converts from an OpenTelemetry SpanContext to an
+// OpenCensus SpanContext, and handles any incompatibilities with the global
+// error handler.
+func OTelSpanContextToOC(sc trace.SpanContext) octrace.SpanContext {
+	return otel2oc.SpanContext(sc)
+}
+
+// OCSpanContextToOTel converts from an OpenCensus SpanContext to an
+// OpenTelemetry SpanContext.
+func OCSpanContextToOTel(sc octrace.SpanContext) trace.SpanContext {
+	return oc2otel.SpanContext(sc)
+}

+ 64 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/README.md

@@ -0,0 +1,64 @@
+# OpenTelemetry/OpenTracing Bridge
+
+## Getting started
+
+`go get go.opentelemetry.io/otel/bridge/opentracing`
+
+Assuming you have configured an OpenTelemetry `TracerProvider`, these will be the steps to follow to wire up the bridge:
+
+```go
+import (
+	"go.opentelemetry.io/otel"
+	otelBridge "go.opentelemetry.io/otel/bridge/opentracing"
+)
+
+func main() {
+	/* Create tracerProvider and configure OpenTelemetry ... */
+	
+	otelTracer := tracerProvider.Tracer("tracer_name")
+	// Use the bridgeTracer as your OpenTracing tracer.
+	bridgeTracer, wrapperTracerProvider := otelBridge.NewTracerPair(otelTracer)
+	// Set the wrapperTracerProvider as the global OpenTelemetry
+	// TracerProvider so instrumentation will use it by default.
+	otel.SetTracerProvider(wrapperTracerProvider)
+
+	/* ... */
+}
+```
+
+## Interop from trace context from OpenTracing to OpenTelemetry
+
+In order to get OpenTracing spans properly into the OpenTelemetry context, so they can be propagated (both internally, and externally), you will need to explicitly use the `BridgeTracer` for creating your OpenTracing spans, rather than a bare OpenTracing `Tracer` instance.
+
+When you have started an OpenTracing Span, make sure the OpenTelemetry knows about it like this:
+
+```go
+	ctxWithOTSpan := opentracing.ContextWithSpan(ctx, otSpan)
+	ctxWithOTAndOTelSpan := bridgeTracer.ContextWithSpanHook(ctxWithOTSpan, otSpan)
+	// Propagate the otSpan to both OpenTracing and OpenTelemetry
+	// instrumentation by using the ctxWithOTAndOTelSpan context.
+```
+
+## Extended Functionality
+
+The bridge functionality can be extended beyond the OpenTracing API.
+
+Any [`trace.SpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#SpanContext) method can be accessed as following:
+
+```go
+type spanContextProvider interface {
+	IsSampled() bool
+	TraceID() trace.TraceID
+	SpanID() trace.SpanID
+	TraceFlags() trace.TraceFlags
+	... // any other available method can be added here to access it
+}
+
+var sc opentracing.SpanContext = ...
+if s, ok := sc.(spanContextProvider); ok {
+	// Use TraceID by s.TraceID()
+	// Use SpanID by s.SpanID()
+	// Use TraceFlags by s.TraceFlags()
+	...
+}
+```

+ 844 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/bridge.go

@@ -0,0 +1,844 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opentracing // import "go.opentelemetry.io/otel/bridge/opentracing"
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"strings"
+	"sync"
+
+	ot "github.com/opentracing/opentracing-go"
+	otext "github.com/opentracing/opentracing-go/ext"
+	otlog "github.com/opentracing/opentracing-go/log"
+
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/baggage"
+	"go.opentelemetry.io/otel/bridge/opentracing/migration"
+	"go.opentelemetry.io/otel/codes"
+	iBaggage "go.opentelemetry.io/otel/internal/baggage"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/trace"
+)
+
+var (
+	noopTracer = trace.NewNoopTracerProvider().Tracer("")
+	noopSpan   = func() trace.Span {
+		_, s := noopTracer.Start(context.Background(), "")
+		return s
+	}()
+)
+
+type bridgeSpanContext struct {
+	bag baggage.Baggage
+	trace.SpanContext
+}
+
+var _ ot.SpanContext = &bridgeSpanContext{}
+
+func newBridgeSpanContext(otelSpanContext trace.SpanContext, parentOtSpanContext ot.SpanContext) *bridgeSpanContext {
+	bCtx := &bridgeSpanContext{
+		bag:         baggage.Baggage{},
+		SpanContext: otelSpanContext,
+	}
+	if parentOtSpanContext != nil {
+		parentOtSpanContext.ForeachBaggageItem(func(key, value string) bool {
+			bCtx.setBaggageItem(key, value)
+			return true
+		})
+	}
+	return bCtx
+}
+
+func (c *bridgeSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
+	for _, m := range c.bag.Members() {
+		if !handler(m.Key(), m.Value()) {
+			return
+		}
+	}
+}
+
+func (c *bridgeSpanContext) setBaggageItem(restrictedKey, value string) {
+	crk := http.CanonicalHeaderKey(restrictedKey)
+	m, err := baggage.NewMember(crk, value)
+	if err != nil {
+		return
+	}
+	c.bag, _ = c.bag.SetMember(m)
+}
+
+func (c *bridgeSpanContext) baggageItem(restrictedKey string) baggage.Member {
+	crk := http.CanonicalHeaderKey(restrictedKey)
+	return c.bag.Member(crk)
+}
+
+type bridgeSpan struct {
+	otelSpan          trace.Span
+	ctx               *bridgeSpanContext
+	tracer            *BridgeTracer
+	skipDeferHook     bool
+	extraBaggageItems map[string]string
+}
+
+var _ ot.Span = &bridgeSpan{}
+
+func newBridgeSpan(otelSpan trace.Span, bridgeSC *bridgeSpanContext, tracer *BridgeTracer) *bridgeSpan {
+	return &bridgeSpan{
+		otelSpan:          otelSpan,
+		ctx:               bridgeSC,
+		tracer:            tracer,
+		skipDeferHook:     false,
+		extraBaggageItems: nil,
+	}
+}
+
+func (s *bridgeSpan) Finish() {
+	s.otelSpan.End()
+}
+
+func (s *bridgeSpan) FinishWithOptions(opts ot.FinishOptions) {
+	var otelOpts []trace.SpanEndOption
+
+	if !opts.FinishTime.IsZero() {
+		otelOpts = append(otelOpts, trace.WithTimestamp(opts.FinishTime))
+	}
+	for _, record := range opts.LogRecords {
+		s.logRecord(record)
+	}
+	for _, data := range opts.BulkLogData {
+		s.logRecord(data.ToLogRecord())
+	}
+	s.otelSpan.End(otelOpts...)
+}
+
+func (s *bridgeSpan) logRecord(record ot.LogRecord) {
+	s.otelSpan.AddEvent(
+		"",
+		trace.WithTimestamp(record.Timestamp),
+		trace.WithAttributes(otLogFieldsToOTelAttrs(record.Fields)...),
+	)
+}
+
+func (s *bridgeSpan) Context() ot.SpanContext {
+	return s.ctx
+}
+
+func (s *bridgeSpan) SetOperationName(operationName string) ot.Span {
+	s.otelSpan.SetName(operationName)
+	return s
+}
+
+// SetTag method adds a tag to the span.
+//
+// Note about the following value conversions:
+// - int -> int64
+// - uint -> string
+// - int32 -> int64
+// - uint32 -> int64
+// - uint64 -> string
+// - float32 -> float64
+func (s *bridgeSpan) SetTag(key string, value interface{}) ot.Span {
+	switch key {
+	case string(otext.SpanKind):
+		// TODO: Should we ignore it?
+	case string(otext.Error):
+		if b, ok := value.(bool); ok && b {
+			s.otelSpan.SetStatus(codes.Error, "")
+		}
+	default:
+		s.otelSpan.SetAttributes(otTagToOTelAttr(key, value))
+	}
+	return s
+}
+
+func (s *bridgeSpan) LogFields(fields ...otlog.Field) {
+	s.otelSpan.AddEvent(
+		"",
+		trace.WithAttributes(otLogFieldsToOTelAttrs(fields)...),
+	)
+}
+
+type bridgeFieldEncoder struct {
+	pairs []attribute.KeyValue
+}
+
+var _ otlog.Encoder = &bridgeFieldEncoder{}
+
+func (e *bridgeFieldEncoder) EmitString(key, value string) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitBool(key string, value bool) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitInt(key string, value int) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitInt32(key string, value int32) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitInt64(key string, value int64) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitUint32(key string, value uint32) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitUint64(key string, value uint64) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitFloat32(key string, value float32) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitFloat64(key string, value float64) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitObject(key string, value interface{}) {
+	e.emitCommon(key, value)
+}
+
+func (e *bridgeFieldEncoder) EmitLazyLogger(value otlog.LazyLogger) {
+	value(e)
+}
+
+func (e *bridgeFieldEncoder) emitCommon(key string, value interface{}) {
+	e.pairs = append(e.pairs, otTagToOTelAttr(key, value))
+}
+
+func otLogFieldsToOTelAttrs(fields []otlog.Field) []attribute.KeyValue {
+	encoder := &bridgeFieldEncoder{}
+	for _, field := range fields {
+		field.Marshal(encoder)
+	}
+	return encoder.pairs
+}
+
+func (s *bridgeSpan) LogKV(alternatingKeyValues ...interface{}) {
+	fields, err := otlog.InterleavedKVToFields(alternatingKeyValues...)
+	if err != nil {
+		return
+	}
+	s.LogFields(fields...)
+}
+
+func (s *bridgeSpan) SetBaggageItem(restrictedKey, value string) ot.Span {
+	s.updateOTelContext(restrictedKey, value)
+	s.setBaggageItemOnly(restrictedKey, value)
+	return s
+}
+
+func (s *bridgeSpan) setBaggageItemOnly(restrictedKey, value string) {
+	s.ctx.setBaggageItem(restrictedKey, value)
+}
+
+func (s *bridgeSpan) updateOTelContext(restrictedKey, value string) {
+	if s.extraBaggageItems == nil {
+		s.extraBaggageItems = make(map[string]string)
+	}
+	s.extraBaggageItems[restrictedKey] = value
+}
+
+func (s *bridgeSpan) BaggageItem(restrictedKey string) string {
+	return s.ctx.baggageItem(restrictedKey).Value()
+}
+
+func (s *bridgeSpan) Tracer() ot.Tracer {
+	return s.tracer
+}
+
+func (s *bridgeSpan) LogEvent(event string) {
+	s.LogEventWithPayload(event, nil)
+}
+
+func (s *bridgeSpan) LogEventWithPayload(event string, payload interface{}) {
+	data := ot.LogData{
+		Event:   event,
+		Payload: payload,
+	}
+	s.Log(data)
+}
+
+func (s *bridgeSpan) Log(data ot.LogData) {
+	record := data.ToLogRecord()
+	s.LogFields(record.Fields...)
+}
+
+type bridgeSetTracer struct {
+	isSet      bool
+	otelTracer trace.Tracer
+
+	warningHandler BridgeWarningHandler
+	warnOnce       sync.Once
+}
+
+func (s *bridgeSetTracer) tracer() trace.Tracer {
+	if !s.isSet {
+		s.warnOnce.Do(func() {
+			s.warningHandler("The OpenTelemetry tracer is not set, default no-op tracer is used! Call SetOpenTelemetryTracer to set it up.\n")
+		})
+	}
+	return s.otelTracer
+}
+
+// BridgeWarningHandler is a type of handler that receives warnings
+// from the BridgeTracer.
+type BridgeWarningHandler func(msg string)
+
+// BridgeTracer is an implementation of the OpenTracing tracer, which
+// translates the calls to the OpenTracing API into OpenTelemetry
+// counterparts and calls the underlying OpenTelemetry tracer.
+type BridgeTracer struct {
+	setTracer bridgeSetTracer
+
+	warningHandler BridgeWarningHandler
+	warnOnce       sync.Once
+
+	propagator propagation.TextMapPropagator
+}
+
+var _ ot.Tracer = &BridgeTracer{}
+var _ ot.TracerContextWithSpanExtension = &BridgeTracer{}
+
+// NewBridgeTracer creates a new BridgeTracer. The new tracer forwards
+// the calls to the OpenTelemetry Noop tracer, so it should be
+// overridden with the SetOpenTelemetryTracer function. The warnings
+// handler does nothing by default, so to override it use the
+// SetWarningHandler function.
+func NewBridgeTracer() *BridgeTracer {
+	return &BridgeTracer{
+		setTracer: bridgeSetTracer{
+			warningHandler: func(msg string) {},
+			otelTracer:     noopTracer,
+		},
+		warningHandler: func(msg string) {},
+		propagator:     nil,
+	}
+}
+
+// SetWarningHandler overrides the warning handler.
+func (t *BridgeTracer) SetWarningHandler(handler BridgeWarningHandler) {
+	t.setTracer.warningHandler = handler
+	t.warningHandler = handler
+}
+
+// SetOpenTelemetryTracer overrides the underlying OpenTelemetry
+// tracer. The passed tracer should know how to operate in the
+// environment that uses OpenTracing API.
+func (t *BridgeTracer) SetOpenTelemetryTracer(tracer trace.Tracer) {
+	t.setTracer.otelTracer = tracer
+	t.setTracer.isSet = true
+}
+
+// SetTextMapPropagator sets propagator as the TextMapPropagator to use by the
+// BridgeTracer.
+func (t *BridgeTracer) SetTextMapPropagator(propagator propagation.TextMapPropagator) {
+	t.propagator = propagator
+}
+
+// NewHookedContext returns a Context that has ctx as its parent and is
+// wrapped to handle baggage set and get operations.
+func (t *BridgeTracer) NewHookedContext(ctx context.Context) context.Context {
+	ctx = iBaggage.ContextWithSetHook(ctx, t.baggageSetHook)
+	ctx = iBaggage.ContextWithGetHook(ctx, t.baggageGetHook)
+	return ctx
+}
+
+func (t *BridgeTracer) baggageSetHook(ctx context.Context, list iBaggage.List) context.Context {
+	span := ot.SpanFromContext(ctx)
+	if span == nil {
+		t.warningHandler("No active OpenTracing span, can not propagate the baggage items from OpenTelemetry context\n")
+		return ctx
+	}
+	bSpan, ok := span.(*bridgeSpan)
+	if !ok {
+		t.warningHandler("Encountered a foreign OpenTracing span, will not propagate the baggage items from OpenTelemetry context\n")
+		return ctx
+	}
+	for k, v := range list {
+		bSpan.setBaggageItemOnly(k, v.Value)
+	}
+	return ctx
+}
+
+func (t *BridgeTracer) baggageGetHook(ctx context.Context, list iBaggage.List) iBaggage.List {
+	span := ot.SpanFromContext(ctx)
+	if span == nil {
+		t.warningHandler("No active OpenTracing span, can not propagate the baggage items from OpenTracing span context\n")
+		return list
+	}
+	bSpan, ok := span.(*bridgeSpan)
+	if !ok {
+		t.warningHandler("Encountered a foreign OpenTracing span, will not propagate the baggage items from OpenTracing span context\n")
+		return list
+	}
+	items := bSpan.extraBaggageItems
+	if len(items) == 0 {
+		return list
+	}
+
+	// Privilege of using the internal representation of Baggage here comes
+	// with the responsibility to make sure we maintain its immutability. We
+	// need to return a copy to ensure this.
+
+	merged := make(iBaggage.List, len(list))
+	for k, v := range list {
+		merged[k] = v
+	}
+
+	for k, v := range items {
+		// Overwrite according to OpenTelemetry specification.
+		merged[k] = iBaggage.Item{Value: v}
+	}
+
+	return merged
+}
+
+// StartSpan is a part of the implementation of the OpenTracing Tracer
+// interface.
+func (t *BridgeTracer) StartSpan(operationName string, opts ...ot.StartSpanOption) ot.Span {
+	sso := ot.StartSpanOptions{}
+	for _, opt := range opts {
+		opt.Apply(&sso)
+	}
+	parentBridgeSC, links := otSpanReferencesToParentAndLinks(sso.References)
+	attributes, kind, hadTrueErrorTag := otTagsToOTelAttributesKindAndError(sso.Tags)
+	checkCtx := migration.WithDeferredSetup(context.Background())
+	if parentBridgeSC != nil {
+		checkCtx = trace.ContextWithRemoteSpanContext(checkCtx, parentBridgeSC.SpanContext)
+	}
+	checkCtx2, otelSpan := t.setTracer.tracer().Start(
+		checkCtx,
+		operationName,
+		trace.WithAttributes(attributes...),
+		trace.WithTimestamp(sso.StartTime),
+		trace.WithLinks(links...),
+		trace.WithSpanKind(kind),
+	)
+	if ot.SpanFromContext(checkCtx2) != nil {
+		t.warnOnce.Do(func() {
+			t.warningHandler("SDK should have deferred the context setup, see the documentation of go.opentelemetry.io/otel/bridge/opentracing/migration\n")
+		})
+	}
+	if hadTrueErrorTag {
+		otelSpan.SetStatus(codes.Error, "")
+	}
+	// One does not simply pass a concrete pointer to function
+	// that takes some interface. In case of passing nil concrete
+	// pointer, we get an interface with non-nil type (because the
+	// pointer type is known) and a nil value. Which means
+	// interface is not nil, but calling some interface function
+	// on it will most likely result in nil pointer dereference.
+	var otSpanContext ot.SpanContext
+	if parentBridgeSC != nil {
+		otSpanContext = parentBridgeSC
+	}
+	sctx := newBridgeSpanContext(otelSpan.SpanContext(), otSpanContext)
+	span := newBridgeSpan(otelSpan, sctx, t)
+
+	return span
+}
+
+// ContextWithBridgeSpan sets up the context with the passed
+// OpenTelemetry span as the active OpenTracing span.
+//
+// This function should be used by the OpenTelemetry tracers that want
+// to be aware how to operate in the environment using OpenTracing
+// API.
+func (t *BridgeTracer) ContextWithBridgeSpan(ctx context.Context, span trace.Span) context.Context {
+	var otSpanContext ot.SpanContext
+	if parentSpan := ot.SpanFromContext(ctx); parentSpan != nil {
+		otSpanContext = parentSpan.Context()
+	}
+	bCtx := newBridgeSpanContext(span.SpanContext(), otSpanContext)
+	bSpan := newBridgeSpan(span, bCtx, t)
+	bSpan.skipDeferHook = true
+	return ot.ContextWithSpan(ctx, bSpan)
+}
+
+// ContextWithSpanHook is an implementation of the OpenTracing tracer
+// extension interface. It will call the DeferredContextSetupHook
+// function on the tracer if it implements the
+// DeferredContextSetupTracerExtension interface.
+func (t *BridgeTracer) ContextWithSpanHook(ctx context.Context, span ot.Span) context.Context {
+	bSpan, ok := span.(*bridgeSpan)
+	if !ok {
+		t.warningHandler("Encountered a foreign OpenTracing span, will not run a possible deferred context setup hook\n")
+		return ctx
+	}
+	if bSpan.skipDeferHook {
+		return ctx
+	}
+	if tracerWithExtension, ok := bSpan.tracer.setTracer.tracer().(migration.DeferredContextSetupTracerExtension); ok {
+		ctx = tracerWithExtension.DeferredContextSetupHook(ctx, bSpan.otelSpan)
+	}
+	return ctx
+}
+
+func otTagsToOTelAttributesKindAndError(tags map[string]interface{}) ([]attribute.KeyValue, trace.SpanKind, bool) {
+	kind := trace.SpanKindInternal
+	err := false
+	var pairs []attribute.KeyValue
+	for k, v := range tags {
+		switch k {
+		case string(otext.SpanKind):
+			sk := v
+			if s, ok := v.(string); ok {
+				sk = otext.SpanKindEnum(strings.ToLower(s))
+			}
+			switch sk {
+			case otext.SpanKindRPCClientEnum:
+				kind = trace.SpanKindClient
+			case otext.SpanKindRPCServerEnum:
+				kind = trace.SpanKindServer
+			case otext.SpanKindProducerEnum:
+				kind = trace.SpanKindProducer
+			case otext.SpanKindConsumerEnum:
+				kind = trace.SpanKindConsumer
+			}
+		case string(otext.Error):
+			if b, ok := v.(bool); ok && b {
+				err = true
+			}
+		default:
+			pairs = append(pairs, otTagToOTelAttr(k, v))
+		}
+	}
+	return pairs, kind, err
+}
+
+// otTagToOTelAttr converts given key-value into attribute.KeyValue.
+// Note that some conversions are not obvious:
+// - int -> int64
+// - uint -> string
+// - int32 -> int64
+// - uint32 -> int64
+// - uint64 -> string
+// - float32 -> float64
+func otTagToOTelAttr(k string, v interface{}) attribute.KeyValue {
+	key := otTagToOTelAttrKey(k)
+	switch val := v.(type) {
+	case bool:
+		return key.Bool(val)
+	case int64:
+		return key.Int64(val)
+	case uint64:
+		return key.String(fmt.Sprintf("%d", val))
+	case float64:
+		return key.Float64(val)
+	case int8:
+		return key.Int64(int64(val))
+	case uint8:
+		return key.Int64(int64(val))
+	case int16:
+		return key.Int64(int64(val))
+	case uint16:
+		return key.Int64(int64(val))
+	case int32:
+		return key.Int64(int64(val))
+	case uint32:
+		return key.Int64(int64(val))
+	case float32:
+		return key.Float64(float64(val))
+	case int:
+		return key.Int(val)
+	case uint:
+		return key.String(fmt.Sprintf("%d", val))
+	case string:
+		return key.String(val)
+	default:
+		return key.String(fmt.Sprint(v))
+	}
+}
+
+func otTagToOTelAttrKey(k string) attribute.Key {
+	return attribute.Key(k)
+}
+
+func otSpanReferencesToParentAndLinks(references []ot.SpanReference) (*bridgeSpanContext, []trace.Link) {
+	var (
+		parent *bridgeSpanContext
+		links  []trace.Link
+	)
+	for _, reference := range references {
+		bridgeSC, ok := reference.ReferencedContext.(*bridgeSpanContext)
+		if !ok {
+			// We ignore foreign ot span contexts,
+			// sorry. We have no way of getting any
+			// TraceID and SpanID out of it for form a
+			// OTel SpanContext for OTel Link. And
+			// we can't make it a parent - it also needs a
+			// valid OTel SpanContext.
+			continue
+		}
+		if parent != nil {
+			links = append(links, otSpanReferenceToOTelLink(bridgeSC, reference.Type))
+		} else {
+			if reference.Type == ot.ChildOfRef {
+				parent = bridgeSC
+			} else {
+				links = append(links, otSpanReferenceToOTelLink(bridgeSC, reference.Type))
+			}
+		}
+	}
+	return parent, links
+}
+
+func otSpanReferenceToOTelLink(bridgeSC *bridgeSpanContext, refType ot.SpanReferenceType) trace.Link {
+	return trace.Link{
+		SpanContext: bridgeSC.SpanContext,
+		Attributes:  otSpanReferenceTypeToOTelLinkAttributes(refType),
+	}
+}
+
+func otSpanReferenceTypeToOTelLinkAttributes(refType ot.SpanReferenceType) []attribute.KeyValue {
+	return []attribute.KeyValue{
+		attribute.String("ot-span-reference-type", otSpanReferenceTypeToString(refType)),
+	}
+}
+
+func otSpanReferenceTypeToString(refType ot.SpanReferenceType) string {
+	switch refType {
+	case ot.ChildOfRef:
+		// "extra", because first child-of reference is used
+		// as a parent, so this function isn't even called for
+		// it.
+		return "extra-child-of"
+	case ot.FollowsFromRef:
+		return "follows-from-ref"
+	default:
+		return fmt.Sprintf("unknown-%d", int(refType))
+	}
+}
+
+// fakeSpan is just a holder of span context, nothing more. It's for
+// propagators, so they can get the span context from Go context.
+type fakeSpan struct {
+	trace.Span
+	sc trace.SpanContext
+}
+
+func (s fakeSpan) SpanContext() trace.SpanContext {
+	return s.sc
+}
+
+// Inject is a part of the implementation of the OpenTracing Tracer
+// interface.
+//
+// Currently only the HTTPHeaders and TextMap formats are supported.
+func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier interface{}) error {
+	bridgeSC, ok := sm.(*bridgeSpanContext)
+	if !ok {
+		return ot.ErrInvalidSpanContext
+	}
+	if !bridgeSC.IsValid() {
+		return ot.ErrInvalidSpanContext
+	}
+
+	builtinFormat, ok := format.(ot.BuiltinFormat)
+	if !ok {
+		return ot.ErrUnsupportedFormat
+	}
+
+	var textCarrier propagation.TextMapCarrier
+	var err error
+
+	switch builtinFormat {
+	case ot.HTTPHeaders:
+		if hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier); ok {
+			textCarrier = propagation.HeaderCarrier(hhcarrier)
+		} else {
+			textCarrier, err = newTextMapWrapperForInject(carrier)
+		}
+	case ot.TextMap:
+		if textCarrier, ok = carrier.(propagation.TextMapCarrier); !ok {
+			textCarrier, err = newTextMapWrapperForInject(carrier)
+		}
+	default:
+		err = ot.ErrUnsupportedFormat
+	}
+	if err != nil {
+		return err
+	}
+
+	fs := fakeSpan{
+		Span: noopSpan,
+		sc:   bridgeSC.SpanContext,
+	}
+	ctx := trace.ContextWithSpan(context.Background(), fs)
+	ctx = baggage.ContextWithBaggage(ctx, bridgeSC.bag)
+	t.getPropagator().Inject(ctx, textCarrier)
+	return nil
+}
+
+// Extract is a part of the implementation of the OpenTracing Tracer
+// interface.
+//
+// Currently only the HTTPHeaders and TextMap formats are supported.
+func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.SpanContext, error) {
+	builtinFormat, ok := format.(ot.BuiltinFormat)
+	if !ok {
+		return nil, ot.ErrUnsupportedFormat
+	}
+
+	var textCarrier propagation.TextMapCarrier
+	var err error
+
+	switch builtinFormat {
+	case ot.HTTPHeaders:
+		if hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier); ok {
+			textCarrier = propagation.HeaderCarrier(hhcarrier)
+		} else {
+			textCarrier, err = newTextMapWrapperForExtract(carrier)
+		}
+	case ot.TextMap:
+		if textCarrier, ok = carrier.(propagation.TextMapCarrier); !ok {
+			textCarrier, err = newTextMapWrapperForExtract(carrier)
+		}
+	default:
+		err = ot.ErrUnsupportedFormat
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	ctx := t.getPropagator().Extract(context.Background(), textCarrier)
+	bag := baggage.FromContext(ctx)
+	bridgeSC := &bridgeSpanContext{
+		bag:         bag,
+		SpanContext: trace.SpanContextFromContext(ctx),
+	}
+	if !bridgeSC.IsValid() {
+		return nil, ot.ErrSpanContextNotFound
+	}
+	return bridgeSC, nil
+}
+
+func (t *BridgeTracer) getPropagator() propagation.TextMapPropagator {
+	if t.propagator != nil {
+		return t.propagator
+	}
+	return otel.GetTextMapPropagator()
+}
+
+// textMapWrapper Provides operating.TextMapWriter and operating.TextMapReader to
+// propagation.TextMapCarrier compatibility.
+// Usually, Inject method will only use the write-related interface.
+// Extract method will only use the reade-related interface.
+// To avoid panic,
+// when the carrier implements only one of the interfaces,
+// it provides a default implementation of the other interface (textMapWriter and textMapReader).
+type textMapWrapper struct {
+	ot.TextMapWriter
+	ot.TextMapReader
+	readerMap map[string]string
+}
+
+func (t *textMapWrapper) Get(key string) string {
+	if t.readerMap == nil {
+		t.loadMap()
+	}
+
+	return t.readerMap[key]
+}
+
+func (t *textMapWrapper) Set(key string, value string) {
+	t.TextMapWriter.Set(key, value)
+}
+
+func (t *textMapWrapper) Keys() []string {
+	if t.readerMap == nil {
+		t.loadMap()
+	}
+
+	str := make([]string, 0, len(t.readerMap))
+	for key := range t.readerMap {
+		str = append(str, key)
+	}
+
+	return str
+}
+
+func (t *textMapWrapper) loadMap() {
+	t.readerMap = make(map[string]string)
+
+	_ = t.ForeachKey(func(key, val string) error {
+		t.readerMap[key] = val
+
+		return nil
+	})
+}
+
+func newTextMapWrapperForExtract(carrier interface{}) (*textMapWrapper, error) {
+	t := &textMapWrapper{}
+
+	reader, ok := carrier.(ot.TextMapReader)
+	if !ok {
+		return nil, ot.ErrInvalidCarrier
+	}
+
+	t.TextMapReader = reader
+
+	writer, ok := carrier.(ot.TextMapWriter)
+	if ok {
+		t.TextMapWriter = writer
+	} else {
+		t.TextMapWriter = &textMapWriter{}
+	}
+
+	return t, nil
+}
+
+func newTextMapWrapperForInject(carrier interface{}) (*textMapWrapper, error) {
+	t := &textMapWrapper{}
+
+	writer, ok := carrier.(ot.TextMapWriter)
+	if !ok {
+		return nil, ot.ErrInvalidCarrier
+	}
+
+	t.TextMapWriter = writer
+
+	reader, ok := carrier.(ot.TextMapReader)
+	if ok {
+		t.TextMapReader = reader
+	} else {
+		t.TextMapReader = &textMapReader{}
+	}
+
+	return t, nil
+}
+
+type textMapWriter struct {
+}
+
+func (t *textMapWriter) Set(key string, value string) {
+	// maybe print a warning log.
+}
+
+type textMapReader struct {
+}
+
+func (t *textMapReader) ForeachKey(handler func(key, val string) error) error {
+	return nil // maybe print a warning log.
+}

+ 578 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/bridge_test.go

@@ -0,0 +1,578 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opentracing
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net/http"
+	"reflect"
+	"strings"
+	"testing"
+
+	ot "github.com/opentracing/opentracing-go"
+	"github.com/opentracing/opentracing-go/ext"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/bridge/opentracing/internal"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/trace"
+)
+
+type testOnlyTextMapReader struct {
+}
+
+func newTestOnlyTextMapReader() *testOnlyTextMapReader {
+	return &testOnlyTextMapReader{}
+}
+
+func (t *testOnlyTextMapReader) ForeachKey(handler func(key string, val string) error) error {
+	_ = handler("key1", "val1")
+	_ = handler("key2", "val2")
+
+	return nil
+}
+
+type testOnlyTextMapWriter struct {
+	m map[string]string
+}
+
+func newTestOnlyTextMapWriter() *testOnlyTextMapWriter {
+	return &testOnlyTextMapWriter{m: map[string]string{}}
+}
+
+func (t *testOnlyTextMapWriter) Set(key, val string) {
+	t.m[key] = val
+}
+
+type testTextMapReaderAndWriter struct {
+	*testOnlyTextMapReader
+	*testOnlyTextMapWriter
+}
+
+func newTestTextMapReaderAndWriter() *testTextMapReaderAndWriter {
+	return &testTextMapReaderAndWriter{
+		testOnlyTextMapReader: newTestOnlyTextMapReader(),
+		testOnlyTextMapWriter: newTestOnlyTextMapWriter(),
+	}
+}
+
+func TestTextMapWrapper_New(t *testing.T) {
+	_, err := newTextMapWrapperForExtract(newTestOnlyTextMapReader())
+	assert.NoError(t, err)
+
+	_, err = newTextMapWrapperForExtract(newTestOnlyTextMapWriter())
+	assert.True(t, errors.Is(err, ot.ErrInvalidCarrier))
+
+	_, err = newTextMapWrapperForExtract(newTestTextMapReaderAndWriter())
+	assert.NoError(t, err)
+
+	_, err = newTextMapWrapperForInject(newTestOnlyTextMapWriter())
+	assert.NoError(t, err)
+
+	_, err = newTextMapWrapperForInject(newTestOnlyTextMapReader())
+	assert.True(t, errors.Is(err, ot.ErrInvalidCarrier))
+
+	_, err = newTextMapWrapperForInject(newTestTextMapReaderAndWriter())
+	assert.NoError(t, err)
+}
+
+func TestTextMapWrapper_action(t *testing.T) {
+	testExtractFunc := func(carrier propagation.TextMapCarrier) {
+		str := carrier.Keys()
+		assert.Len(t, str, 2)
+		assert.Contains(t, str, "key1", "key2")
+
+		assert.Equal(t, carrier.Get("key1"), "val1")
+		assert.Equal(t, carrier.Get("key2"), "val2")
+	}
+
+	testInjectFunc := func(carrier propagation.TextMapCarrier) {
+		carrier.Set("key1", "val1")
+		carrier.Set("key2", "val2")
+
+		wrap, ok := carrier.(*textMapWrapper)
+		assert.True(t, ok)
+
+		writer, ok := wrap.TextMapWriter.(*testOnlyTextMapWriter)
+		if ok {
+			assert.Contains(t, writer.m, "key1", "key2", "val1", "val2")
+			return
+		}
+
+		writer2, ok := wrap.TextMapWriter.(*testTextMapReaderAndWriter)
+		assert.True(t, ok)
+		assert.Contains(t, writer2.m, "key1", "key2", "val1", "val2")
+	}
+
+	onlyWriter, err := newTextMapWrapperForExtract(newTestOnlyTextMapReader())
+	assert.NoError(t, err)
+	testExtractFunc(onlyWriter)
+
+	onlyReader, err := newTextMapWrapperForInject(&testOnlyTextMapWriter{m: map[string]string{}})
+	assert.NoError(t, err)
+	testInjectFunc(onlyReader)
+
+	both, err := newTextMapWrapperForExtract(newTestTextMapReaderAndWriter())
+	assert.NoError(t, err)
+	testExtractFunc(both)
+
+	both, err = newTextMapWrapperForInject(newTestTextMapReaderAndWriter())
+	assert.NoError(t, err)
+	testInjectFunc(both)
+}
+
+var (
+	testHeader               = "test-trace-id"
+	traceID    trace.TraceID = [16]byte{byte(10)}
+	spanID     trace.SpanID  = [8]byte{byte(11)}
+)
+
+type testTextMapPropagator struct {
+}
+
+func (t testTextMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) {
+	carrier.Set(testHeader, strings.Join([]string{traceID.String(), spanID.String()}, ":"))
+
+	// Test for panic
+	_ = carrier.Get("test")
+	_ = carrier.Keys()
+}
+
+func (t testTextMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context {
+	traces := carrier.Get(testHeader)
+
+	str := strings.Split(traces, ":")
+	if len(str) != 2 {
+		return ctx
+	}
+
+	var exist = false
+
+	for _, key := range carrier.Keys() {
+		if strings.EqualFold(testHeader, key) {
+			exist = true
+
+			break
+		}
+	}
+
+	if !exist {
+		return ctx
+	}
+
+	var (
+		traceID, _ = trace.TraceIDFromHex(str[0])
+		spanID, _  = trace.SpanIDFromHex(str[1])
+		sc         = trace.NewSpanContext(trace.SpanContextConfig{
+			TraceID: traceID,
+			SpanID:  spanID,
+		})
+	)
+
+	// Test for panic
+	carrier.Set("key", "val")
+
+	return trace.ContextWithRemoteSpanContext(ctx, sc)
+}
+
+func (t testTextMapPropagator) Fields() []string {
+	return []string{"test"}
+}
+
+// textMapCarrier  Implemented propagation.TextMapCarrier interface.
+type textMapCarrier struct {
+	m map[string]string
+}
+
+var _ propagation.TextMapCarrier = (*textMapCarrier)(nil)
+
+func newTextCarrier() *textMapCarrier {
+	return &textMapCarrier{m: map[string]string{}}
+}
+
+func (t *textMapCarrier) Get(key string) string {
+	return t.m[key]
+}
+
+func (t *textMapCarrier) Set(key string, value string) {
+	t.m[key] = value
+}
+
+func (t *textMapCarrier) Keys() []string {
+	str := make([]string, 0, len(t.m))
+
+	for key := range t.m {
+		str = append(str, key)
+	}
+
+	return str
+}
+
+// testTextMapReader only implemented opentracing.TextMapReader interface.
+type testTextMapReader struct {
+	m *map[string]string
+}
+
+func newTestTextMapReader(m *map[string]string) *testTextMapReader {
+	return &testTextMapReader{m: m}
+}
+
+func (t *testTextMapReader) ForeachKey(handler func(key string, val string) error) error {
+	for key, val := range *t.m {
+		if err := handler(key, val); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// testTextMapWriter only implemented opentracing.TextMapWriter interface.
+type testTextMapWriter struct {
+	m *map[string]string
+}
+
+func newTestTextMapWriter(m *map[string]string) *testTextMapWriter {
+	return &testTextMapWriter{m: m}
+}
+
+func (t *testTextMapWriter) Set(key, val string) {
+	(*t.m)[key] = val
+}
+
+type samplable interface {
+	IsSampled() bool
+}
+
+func TestBridgeTracer_ExtractAndInject(t *testing.T) {
+	bridge := NewBridgeTracer()
+	bridge.SetTextMapPropagator(new(testTextMapPropagator))
+
+	tmc := newTextCarrier()
+	shareMap := map[string]string{}
+	otTextMap := ot.TextMapCarrier{}
+	httpHeader := ot.HTTPHeadersCarrier(http.Header{})
+
+	testCases := []struct {
+		name               string
+		injectCarrierType  ot.BuiltinFormat
+		extractCarrierType ot.BuiltinFormat
+		extractCarrier     interface{}
+		injectCarrier      interface{}
+		extractErr         error
+		injectErr          error
+	}{
+		{
+			name:               "support for propagation.TextMapCarrier",
+			injectCarrierType:  ot.TextMap,
+			injectCarrier:      tmc,
+			extractCarrierType: ot.TextMap,
+			extractCarrier:     tmc,
+		},
+		{
+			name:               "support for opentracing.TextMapReader and opentracing.TextMapWriter",
+			injectCarrierType:  ot.TextMap,
+			injectCarrier:      otTextMap,
+			extractCarrierType: ot.TextMap,
+			extractCarrier:     otTextMap,
+		},
+		{
+			name:               "support for HTTPHeaders",
+			injectCarrierType:  ot.HTTPHeaders,
+			injectCarrier:      httpHeader,
+			extractCarrierType: ot.HTTPHeaders,
+			extractCarrier:     httpHeader,
+		},
+		{
+			name:               "support for opentracing.TextMapReader and opentracing.TextMapWriter,non-same instance",
+			injectCarrierType:  ot.TextMap,
+			injectCarrier:      newTestTextMapWriter(&shareMap),
+			extractCarrierType: ot.TextMap,
+			extractCarrier:     newTestTextMapReader(&shareMap),
+		},
+		{
+			name:              "inject: format type is HTTPHeaders, but carrier is not HTTPHeadersCarrier",
+			injectCarrierType: ot.HTTPHeaders,
+			injectCarrier:     struct{}{},
+			injectErr:         ot.ErrInvalidCarrier,
+		},
+		{
+			name:               "extract: format type is HTTPHeaders, but carrier is not HTTPHeadersCarrier",
+			injectCarrierType:  ot.HTTPHeaders,
+			injectCarrier:      httpHeader,
+			extractCarrierType: ot.HTTPHeaders,
+			extractCarrier:     struct{}{},
+			extractErr:         ot.ErrInvalidCarrier,
+		},
+		{
+			name:              "inject: format type is TextMap, but carrier is cannot be wrapped into propagation.TextMapCarrier",
+			injectCarrierType: ot.TextMap,
+			injectCarrier:     struct{}{},
+			injectErr:         ot.ErrInvalidCarrier,
+		},
+		{
+			name:               "extract: format type is TextMap, but carrier is cannot be wrapped into propagation.TextMapCarrier",
+			injectCarrierType:  ot.TextMap,
+			injectCarrier:      otTextMap,
+			extractCarrierType: ot.TextMap,
+			extractCarrier:     struct{}{},
+			extractErr:         ot.ErrInvalidCarrier,
+		},
+		{
+			name:              "inject: unsupported format type",
+			injectCarrierType: ot.Binary,
+			injectErr:         ot.ErrUnsupportedFormat,
+		},
+		{
+			name:               "extract: unsupported format type",
+			injectCarrierType:  ot.TextMap,
+			injectCarrier:      otTextMap,
+			extractCarrierType: ot.Binary,
+			extractCarrier:     struct{}{},
+			extractErr:         ot.ErrUnsupportedFormat,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			err := bridge.Inject(newBridgeSpanContext(trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: [16]byte{byte(1)},
+				SpanID:  [8]byte{byte(2)},
+			}), nil), tc.injectCarrierType, tc.injectCarrier)
+			assert.Equal(t, tc.injectErr, err)
+
+			if tc.injectErr == nil {
+				spanContext, err := bridge.Extract(tc.extractCarrierType, tc.extractCarrier)
+				assert.Equal(t, tc.extractErr, err)
+
+				if tc.extractErr == nil {
+					bsc, ok := spanContext.(*bridgeSpanContext)
+					assert.True(t, ok)
+					require.NotNil(t, bsc)
+					require.NotNil(t, bsc.SpanContext)
+					require.NotNil(t, bsc.SpanID())
+					require.NotNil(t, bsc.TraceID())
+
+					assert.Equal(t, spanID.String(), bsc.SpanID().String())
+					assert.Equal(t, traceID.String(), bsc.TraceID().String())
+				}
+			}
+		})
+	}
+}
+
+type nonDeferWrapperTracer struct {
+	*WrapperTracer
+}
+
+func (t *nonDeferWrapperTracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
+	// Run start on the parent wrapper with a brand new context
+	// so `WithDeferredSetup` hasn't been called, and the OpenTracing context is injected.
+	return t.WrapperTracer.Start(context.Background(), name, opts...)
+}
+
+func TestBridgeTracer_StartSpan(t *testing.T) {
+	testCases := []struct {
+		name           string
+		before         func(*testing.T, *BridgeTracer)
+		expectWarnings []string
+	}{
+		{
+			name: "with no option set",
+			expectWarnings: []string{
+				"The OpenTelemetry tracer is not set, default no-op tracer is used! Call SetOpenTelemetryTracer to set it up.\n",
+			},
+		},
+		{
+			name: "with wrapper tracer set",
+			before: func(t *testing.T, bridge *BridgeTracer) {
+				wTracer := NewWrapperTracer(bridge, otel.Tracer("test"))
+				bridge.SetOpenTelemetryTracer(wTracer)
+			},
+			expectWarnings: []string(nil),
+		},
+		{
+			name: "with a non-defered wrapper tracer",
+			before: func(t *testing.T, bridge *BridgeTracer) {
+				wTracer := &nonDeferWrapperTracer{
+					NewWrapperTracer(bridge, otel.Tracer("test")),
+				}
+				bridge.SetOpenTelemetryTracer(wTracer)
+			},
+			expectWarnings: []string{
+				"SDK should have deferred the context setup, see the documentation of go.opentelemetry.io/otel/bridge/opentracing/migration\n",
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			var warningMessages []string
+			bridge := NewBridgeTracer()
+			bridge.SetWarningHandler(func(msg string) {
+				warningMessages = append(warningMessages, msg)
+			})
+
+			if tc.before != nil {
+				tc.before(t, bridge)
+			}
+
+			span := bridge.StartSpan("test")
+			assert.NotNil(t, span)
+
+			assert.Equal(t, tc.expectWarnings, warningMessages)
+		})
+	}
+}
+
+func Test_otTagToOTelAttr(t *testing.T) {
+	key := attribute.Key("test")
+	testCases := []struct {
+		value    interface{}
+		expected attribute.KeyValue
+	}{
+		{
+			value:    int8(12),
+			expected: key.Int64(int64(12)),
+		},
+		{
+			value:    uint8(12),
+			expected: key.Int64(int64(12)),
+		},
+		{
+			value:    int16(12),
+			expected: key.Int64(int64(12)),
+		},
+		{
+			value:    uint16(12),
+			expected: key.Int64(int64(12)),
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s %v", reflect.TypeOf(tc.value), tc.value), func(t *testing.T) {
+			att := otTagToOTelAttr(string(key), tc.value)
+			assert.Equal(t, tc.expected, att)
+		})
+	}
+}
+
+func Test_otTagsToOTelAttributesKindAndError(t *testing.T) {
+	tracer := internal.NewMockTracer()
+	sc := &bridgeSpanContext{}
+
+	testCases := []struct {
+		name     string
+		opt      []ot.StartSpanOption
+		expected trace.SpanKind
+	}{
+		{
+			name:     "client",
+			opt:      []ot.StartSpanOption{ext.SpanKindRPCClient},
+			expected: trace.SpanKindClient,
+		},
+		{
+			name:     "server",
+			opt:      []ot.StartSpanOption{ext.RPCServerOption(sc)},
+			expected: trace.SpanKindServer,
+		},
+		{
+			name:     "client string",
+			opt:      []ot.StartSpanOption{ot.Tag{Key: "span.kind", Value: "client"}},
+			expected: trace.SpanKindClient,
+		},
+		{
+			name:     "server string",
+			opt:      []ot.StartSpanOption{ot.Tag{Key: "span.kind", Value: "server"}},
+			expected: trace.SpanKindServer,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			b, _ := NewTracerPair(tracer)
+
+			s := b.StartSpan(tc.name, tc.opt...)
+			assert.Equal(t, s.(*bridgeSpan).otelSpan.(*internal.MockSpan).SpanKind, tc.expected)
+		})
+	}
+}
+
+func TestBridge_SpanContext_IsSampled(t *testing.T) {
+	testCases := []struct {
+		name     string
+		flags    trace.TraceFlags
+		expected bool
+	}{
+		{
+			name:     "not sampled",
+			flags:    0,
+			expected: false,
+		},
+		{
+			name:     "sampled",
+			flags:    trace.FlagsSampled,
+			expected: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			tracer := internal.NewMockTracer()
+			tracer.TraceFlags = tc.flags
+
+			b, _ := NewTracerPair(tracer)
+			s := b.StartSpan("abc")
+			sc := s.Context()
+
+			assert.Equal(t, tc.expected, sc.(samplable).IsSampled())
+		})
+	}
+}
+
+func TestBridgeSpanContextPromotedMethods(t *testing.T) {
+	bridge := NewBridgeTracer()
+	bridge.SetTextMapPropagator(new(testTextMapPropagator))
+
+	tmc := newTextCarrier()
+
+	type spanContextProvider interface {
+		HasTraceID() bool
+		TraceID() trace.TraceID
+		HasSpanID() bool
+		SpanID() trace.SpanID
+	}
+
+	err := bridge.Inject(newBridgeSpanContext(trace.NewSpanContext(trace.SpanContextConfig{
+		TraceID: [16]byte{byte(1)},
+		SpanID:  [8]byte{byte(2)},
+	}), nil), ot.TextMap, tmc)
+	assert.NoError(t, err)
+
+	spanContext, err := bridge.Extract(ot.TextMap, tmc)
+	assert.NoError(t, err)
+
+	assert.NotPanics(t, func() {
+		assert.Equal(t, spanID.String(), spanContext.(spanContextProvider).SpanID().String())
+		assert.Equal(t, traceID.String(), spanContext.(spanContextProvider).TraceID().String())
+		assert.True(t, spanContext.(spanContextProvider).HasSpanID())
+		assert.True(t, spanContext.(spanContextProvider).HasTraceID())
+	})
+}

+ 105 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/doc.go

@@ -0,0 +1,105 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package opentracing implements a bridge that forwards OpenTracing API
+// calls to the OpenTelemetry SDK.
+//
+// To use the bridge, first create an OpenTelemetry tracer of
+// choice. Then use the NewTracerPair() function to create two tracers
+// - one implementing OpenTracing API (BridgeTracer) and one that
+// implements the OpenTelemetry API (WrapperTracer) and mostly
+// forwards the calls to the OpenTelemetry tracer of choice, but does
+// some extra steps to make the interaction between both APIs
+// working. If the OpenTelemetry tracer of choice already knows how to
+// cooperate with OpenTracing API through the OpenTracing bridge
+// (explained in detail below), then it is fine to skip the
+// WrapperTracer by calling the NewBridgeTracer() function to get the
+// bridge tracer and then passing the chosen OpenTelemetry tracer to
+// the SetOpenTelemetryTracer() function of the bridge tracer.
+//
+// To use an OpenTelemetry span as the parent of an OpenTracing span,
+// create a context using the ContextWithBridgeSpan() function of
+// the bridge tracer, and then use the StartSpanFromContext function
+// of the OpenTracing API.
+//
+// Bridge tracer also allows the user to install a warning handler
+// through the SetWarningHandler() function. The warning handler will
+// be called when there is some misbehavior of the OpenTelemetry
+// tracer with regard to the cooperation with the OpenTracing API.
+//
+// For an OpenTelemetry tracer to cooperate with OpenTracing API
+// through the BridgeTracer, the OpenTelemetry tracer needs to
+// (reasoning is below the list):
+//
+// 1. Return the same context it received in the Start() function if
+// migration.SkipContextSetup() returns true.
+//
+// 2. Implement the migration.DeferredContextSetupTracerExtension
+// interface. The implementation should setup the context it would
+// normally do in the Start() function if the
+// migration.SkipContextSetup() function returned false. Calling
+// ContextWithBridgeSpan() is not necessary.
+//
+// 3. Have an access to the BridgeTracer instance.
+//
+// 4. If the migration.SkipContextSetup() function returned false, the
+// tracer should use the ContextWithBridgeSpan() function to install the
+// created span as an active OpenTracing span.
+//
+// There are some differences between OpenTracing and OpenTelemetry
+// APIs, especially with regard to Go context handling. When a span is
+// created with an OpenTracing API (through the StartSpan() function)
+// the Go context is not available. BridgeTracer has access to the
+// OpenTelemetry tracer of choice, so in the StartSpan() function
+// BridgeTracer translates the parameters to the OpenTelemetry version
+// and uses the OpenTelemetry tracer's Start() function to actually
+// create a span. The OpenTelemetry Start() function takes the Go
+// context as a parameter, so BridgeTracer at this point passes a
+// temporary context to Start(). All the changes to the temporary
+// context will be lost at the end of the StartSpan() function, so the
+// OpenTelemetry tracer of choice should not do anything with the
+// context. If the returned context is different, BridgeTracer will
+// warn about it. The OpenTelemetry tracer of choice can learn about
+// this situation by using the migration.SkipContextSetup()
+// function. The tracer will receive an opportunity to set up the
+// context at a later stage. Usually after StartSpan() is finished,
+// users of the OpenTracing API are calling (either directly or
+// through the opentracing.StartSpanFromContext() helper function) the
+// opentracing.ContextWithSpan() function to insert the created
+// OpenTracing span into the context. At that time, the OpenTelemetry
+// tracer of choice has a chance of setting up the context through a
+// hook invoked inside the opentracing.ContextWithSpan() function. For
+// that to happen, the tracer should implement the
+// migration.DeferredContextSetupTracerExtension interface. This so
+// far explains the need for points 1. and 2.
+//
+// When the span is created with the OpenTelemetry API (with the
+// Start() function) then migration.SkipContextSetup() will return
+// false. This means that the tracer can do the usual setup of the
+// context, but it also should set up the active OpenTracing span in
+// the context. This is because OpenTracing API is not used at all in
+// the creation of the span, but the OpenTracing API may be used
+// during the time when the created OpenTelemetry span is current. For
+// this case to work, we need to also set up active OpenTracing span
+// in the context. This can be done with the ContextWithBridgeSpan()
+// function. This means that the OpenTelemetry tracer of choice needs
+// to have an access to the BridgeTracer instance. This should explain
+// the need for points 3. and 4.
+//
+// Another difference related to the Go context handling is in logging
+// - OpenTracing API does not take a context parameter in the
+// LogFields() function, so when the call to the function gets
+// translated to OpenTelemetry AddEvent() function, an empty context
+// is passed.
+package opentracing // import "go.opentelemetry.io/otel/bridge/opentracing"

+ 25 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/go.mod

@@ -0,0 +1,25 @@
+module go.opentelemetry.io/otel/bridge/opentracing
+
+go 1.20
+
+replace go.opentelemetry.io/otel => ../..
+
+replace go.opentelemetry.io/otel/trace => ../../trace
+
+require (
+	github.com/opentracing/opentracing-go v1.2.0
+	github.com/stretchr/testify v1.8.4
+	go.opentelemetry.io/otel v1.19.0
+	go.opentelemetry.io/otel/trace v1.19.0
+)
+
+require (
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/go-logr/logr v1.2.4 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	go.opentelemetry.io/otel/metric v1.19.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
+
+replace go.opentelemetry.io/otel/metric => ../../metric

+ 21 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/go.sum

@@ -0,0 +1,21 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 15 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/internal/doc.go

@@ -0,0 +1,15 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opentelemetry.io/otel/bridge/opentracing/internal"

+ 294 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/internal/mock.go

@@ -0,0 +1,294 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opentelemetry.io/otel/bridge/opentracing/internal"
+
+import (
+	"context"
+	"math/rand"
+	"reflect"
+	"sync"
+	"time"
+
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/bridge/opentracing/migration"
+	"go.opentelemetry.io/otel/codes"
+	semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
+	"go.opentelemetry.io/otel/trace"
+)
+
+//nolint:revive // ignoring missing comments for unexported global variables in an internal package.
+var (
+	ComponentKey     = attribute.Key("component")
+	ServiceKey       = attribute.Key("service")
+	StatusCodeKey    = attribute.Key("status.code")
+	StatusMessageKey = attribute.Key("status.message")
+	ErrorKey         = attribute.Key("error")
+	NameKey          = attribute.Key("name")
+)
+
+type MockContextKeyValue struct {
+	Key   interface{}
+	Value interface{}
+}
+
+type MockTracer struct {
+	FinishedSpans         []*MockSpan
+	SpareTraceIDs         []trace.TraceID
+	SpareSpanIDs          []trace.SpanID
+	SpareContextKeyValues []MockContextKeyValue
+	TraceFlags            trace.TraceFlags
+
+	randLock sync.Mutex
+	rand     *rand.Rand
+}
+
+var _ trace.Tracer = &MockTracer{}
+var _ migration.DeferredContextSetupTracerExtension = &MockTracer{}
+
+func NewMockTracer() *MockTracer {
+	return &MockTracer{
+		FinishedSpans:         nil,
+		SpareTraceIDs:         nil,
+		SpareSpanIDs:          nil,
+		SpareContextKeyValues: nil,
+
+		rand: rand.New(rand.NewSource(time.Now().Unix())),
+	}
+}
+
+func (t *MockTracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
+	config := trace.NewSpanStartConfig(opts...)
+	startTime := config.Timestamp()
+	if startTime.IsZero() {
+		startTime = time.Now()
+	}
+	spanContext := trace.NewSpanContext(trace.SpanContextConfig{
+		TraceID:    t.getTraceID(ctx, &config),
+		SpanID:     t.getSpanID(),
+		TraceFlags: t.TraceFlags,
+	})
+	span := &MockSpan{
+		mockTracer:     t,
+		officialTracer: t,
+		spanContext:    spanContext,
+		Attributes:     config.Attributes(),
+		StartTime:      startTime,
+		EndTime:        time.Time{},
+		ParentSpanID:   t.getParentSpanID(ctx, &config),
+		Events:         nil,
+		SpanKind:       trace.ValidateSpanKind(config.SpanKind()),
+	}
+	if !migration.SkipContextSetup(ctx) {
+		ctx = trace.ContextWithSpan(ctx, span)
+		ctx = t.addSpareContextValue(ctx)
+	}
+	return ctx, span
+}
+
+func (t *MockTracer) addSpareContextValue(ctx context.Context) context.Context {
+	if len(t.SpareContextKeyValues) > 0 {
+		pair := t.SpareContextKeyValues[0]
+		t.SpareContextKeyValues[0] = MockContextKeyValue{}
+		t.SpareContextKeyValues = t.SpareContextKeyValues[1:]
+		if len(t.SpareContextKeyValues) == 0 {
+			t.SpareContextKeyValues = nil
+		}
+		ctx = context.WithValue(ctx, pair.Key, pair.Value)
+	}
+	return ctx
+}
+
+func (t *MockTracer) getTraceID(ctx context.Context, config *trace.SpanConfig) trace.TraceID {
+	if parent := t.getParentSpanContext(ctx, config); parent.IsValid() {
+		return parent.TraceID()
+	}
+	if len(t.SpareTraceIDs) > 0 {
+		traceID := t.SpareTraceIDs[0]
+		t.SpareTraceIDs = t.SpareTraceIDs[1:]
+		if len(t.SpareTraceIDs) == 0 {
+			t.SpareTraceIDs = nil
+		}
+		return traceID
+	}
+	return t.getRandTraceID()
+}
+
+func (t *MockTracer) getParentSpanID(ctx context.Context, config *trace.SpanConfig) trace.SpanID {
+	if parent := t.getParentSpanContext(ctx, config); parent.IsValid() {
+		return parent.SpanID()
+	}
+	return trace.SpanID{}
+}
+
+func (t *MockTracer) getParentSpanContext(ctx context.Context, config *trace.SpanConfig) trace.SpanContext {
+	if !config.NewRoot() {
+		return trace.SpanContextFromContext(ctx)
+	}
+	return trace.SpanContext{}
+}
+
+func (t *MockTracer) getSpanID() trace.SpanID {
+	if len(t.SpareSpanIDs) > 0 {
+		spanID := t.SpareSpanIDs[0]
+		t.SpareSpanIDs = t.SpareSpanIDs[1:]
+		if len(t.SpareSpanIDs) == 0 {
+			t.SpareSpanIDs = nil
+		}
+		return spanID
+	}
+	return t.getRandSpanID()
+}
+
+func (t *MockTracer) getRandSpanID() trace.SpanID {
+	t.randLock.Lock()
+	defer t.randLock.Unlock()
+
+	sid := trace.SpanID{}
+	_, _ = t.rand.Read(sid[:])
+
+	return sid
+}
+
+func (t *MockTracer) getRandTraceID() trace.TraceID {
+	t.randLock.Lock()
+	defer t.randLock.Unlock()
+
+	tid := trace.TraceID{}
+	_, _ = t.rand.Read(tid[:])
+
+	return tid
+}
+
+func (t *MockTracer) DeferredContextSetupHook(ctx context.Context, span trace.Span) context.Context {
+	return t.addSpareContextValue(ctx)
+}
+
+type MockEvent struct {
+	Timestamp  time.Time
+	Name       string
+	Attributes []attribute.KeyValue
+}
+
+type MockSpan struct {
+	mockTracer     *MockTracer
+	officialTracer trace.Tracer
+	spanContext    trace.SpanContext
+	SpanKind       trace.SpanKind
+	recording      bool
+
+	Attributes   []attribute.KeyValue
+	StartTime    time.Time
+	EndTime      time.Time
+	ParentSpanID trace.SpanID
+	Events       []MockEvent
+}
+
+var _ trace.Span = &MockSpan{}
+var _ migration.OverrideTracerSpanExtension = &MockSpan{}
+
+func (s *MockSpan) SpanContext() trace.SpanContext {
+	return s.spanContext
+}
+
+func (s *MockSpan) IsRecording() bool {
+	return s.recording
+}
+
+func (s *MockSpan) SetStatus(code codes.Code, msg string) {
+	s.SetAttributes(StatusCodeKey.Int(int(code)), StatusMessageKey.String(msg))
+}
+
+func (s *MockSpan) SetName(name string) {
+	s.SetAttributes(NameKey.String(name))
+}
+
+func (s *MockSpan) SetError(v bool) {
+	s.SetAttributes(ErrorKey.Bool(v))
+}
+
+func (s *MockSpan) SetAttributes(attributes ...attribute.KeyValue) {
+	s.applyUpdate(attributes)
+}
+
+func (s *MockSpan) applyUpdate(update []attribute.KeyValue) {
+	updateM := make(map[attribute.Key]attribute.Value, len(update))
+	for _, kv := range update {
+		updateM[kv.Key] = kv.Value
+	}
+
+	seen := make(map[attribute.Key]struct{})
+	for i, kv := range s.Attributes {
+		if v, ok := updateM[kv.Key]; ok {
+			s.Attributes[i].Value = v
+			seen[kv.Key] = struct{}{}
+		}
+	}
+
+	for k, v := range updateM {
+		if _, ok := seen[k]; ok {
+			continue
+		}
+		s.Attributes = append(s.Attributes, attribute.KeyValue{Key: k, Value: v})
+	}
+}
+
+func (s *MockSpan) End(options ...trace.SpanEndOption) {
+	if !s.EndTime.IsZero() {
+		return // already finished
+	}
+	config := trace.NewSpanEndConfig(options...)
+	endTime := config.Timestamp()
+	if endTime.IsZero() {
+		endTime = time.Now()
+	}
+	s.EndTime = endTime
+	s.mockTracer.FinishedSpans = append(s.mockTracer.FinishedSpans, s)
+}
+
+func (s *MockSpan) RecordError(err error, opts ...trace.EventOption) {
+	if err == nil {
+		return // no-op on nil error
+	}
+
+	if !s.EndTime.IsZero() {
+		return // already finished
+	}
+
+	s.SetStatus(codes.Error, "")
+	opts = append(opts, trace.WithAttributes(
+		semconv.ExceptionType(reflect.TypeOf(err).String()),
+		semconv.ExceptionMessage(err.Error()),
+	))
+	s.AddEvent(semconv.ExceptionEventName, opts...)
+}
+
+func (s *MockSpan) Tracer() trace.Tracer {
+	return s.officialTracer
+}
+
+func (s *MockSpan) AddEvent(name string, o ...trace.EventOption) {
+	c := trace.NewEventConfig(o...)
+	s.Events = append(s.Events, MockEvent{
+		Timestamp:  c.Timestamp(),
+		Name:       name,
+		Attributes: c.Attributes(),
+	})
+}
+
+func (s *MockSpan) OverrideTracer(tracer trace.Tracer) {
+	s.officialTracer = tracer
+}
+
+func (s *MockSpan) TracerProvider() trace.TracerProvider { return trace.NewNoopTracerProvider() }

+ 76 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/migration/api.go

@@ -0,0 +1,76 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package migration provides interfaces and functions that are useful for
+// providing a cooperation of the OpenTelemetry tracers with the
+// OpenTracing API.
+package migration // import "go.opentelemetry.io/otel/bridge/opentracing/migration"
+
+import (
+	"context"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+// DeferredContextSetupTracerExtension is an interface an
+// OpenTelemetry tracer may implement in order to cooperate with the
+// calls to the OpenTracing API.
+//
+// Tracers implementing this interface should also use the
+// SkipContextSetup() function during creation of the span in the
+// Start() function to skip the configuration of the context.
+type DeferredContextSetupTracerExtension interface {
+	// DeferredContextSetupHook is called by the bridge
+	// OpenTracing tracer when opentracing.ContextWithSpan is
+	// called. This allows the OpenTelemetry tracer to set up the
+	// context in a way it would normally do during the Start()
+	// function. Since OpenTracing API does not support
+	// configuration of the context during span creation, it needs
+	// to be deferred until the call to the
+	// opentracing.ContextWithSpan happens. When bridge
+	// OpenTracing tracer calls OpenTelemetry tracer's Start()
+	// function, it passes a context that shouldn't be modified.
+	DeferredContextSetupHook(ctx context.Context, span trace.Span) context.Context
+}
+
+// OverrideTracerSpanExtension is an interface an OpenTelemetry span
+// may implement in order to cooperate with the calls to the
+// OpenTracing API.
+//
+// TODO(krnowak): I'm actually not so sold on the idea… The reason for
+// introducing this interface was to have a span "created" by the
+// WrapperTracer return WrapperTracer from the Tracer() function, not
+// the real OpenTelemetry tracer that actually created the span. I'm
+// thinking that I could create a wrapperSpan type that wraps an
+// OpenTelemetry Span object and have WrapperTracer to alter the
+// current OpenTelemetry span in the context so it points to the
+// wrapped object, so the code in the tracer like
+// `trace.SpanFromContent().(*realSpan)` would still work. Another
+// argument for getting rid of this interface is that is only called
+// by the WrapperTracer - WrapperTracer likely shouldn't require any
+// changes in the underlying OpenTelemetry tracer to have things
+// somewhat working.
+//
+// See the "tracer mess" test in mix_test.go.
+type OverrideTracerSpanExtension interface {
+	// OverrideTracer makes the span to return the passed tracer
+	// from its Tracer() function.
+	//
+	// You don't need to implement this function if your
+	// OpenTelemetry tracer cooperates well with the OpenTracing
+	// API calls. In such case, there is no need to use the
+	// WrapperTracer and thus no need to override the result of
+	// the Tracer() function.
+	OverrideTracer(tracer trace.Tracer)
+}

+ 39 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/migration/defer.go

@@ -0,0 +1,39 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package migration // import "go.opentelemetry.io/otel/bridge/opentracing/migration"
+
+import (
+	"context"
+)
+
+type doDeferredContextSetupType struct{}
+
+var (
+	doDeferredContextSetupTypeKey   = doDeferredContextSetupType{}
+	doDeferredContextSetupTypeValue = doDeferredContextSetupType{}
+)
+
+// WithDeferredSetup returns a context that can tell the OpenTelemetry
+// tracer to skip the context setup in the Start() function.
+func WithDeferredSetup(ctx context.Context) context.Context {
+	return context.WithValue(ctx, doDeferredContextSetupTypeKey, doDeferredContextSetupTypeValue)
+}
+
+// SkipContextSetup can tell the OpenTelemetry tracer to skip the
+// context setup during the span creation in the Start() function.
+func SkipContextSetup(ctx context.Context) bool {
+	_, ok := ctx.Value(doDeferredContextSetupTypeKey).(doDeferredContextSetupType)
+	return ok
+}

+ 727 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/mix_test.go

@@ -0,0 +1,727 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opentracing
+
+import (
+	"context"
+	"fmt"
+	"testing"
+
+	ot "github.com/opentracing/opentracing-go"
+
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/baggage"
+	"go.opentelemetry.io/otel/bridge/opentracing/internal"
+	"go.opentelemetry.io/otel/trace"
+)
+
+type mixedAPIsTestCase struct {
+	desc string
+
+	setup func(*testing.T, *internal.MockTracer)
+	run   func(*testing.T, context.Context)
+	check func(*testing.T, *internal.MockTracer)
+}
+
+func getMixedAPIsTestCases() []mixedAPIsTestCase {
+	st := newSimpleTest()
+	cast := newCurrentActiveSpanTest()
+	coin := newContextIntactTest()
+	bip := newBaggageItemsPreservationTest()
+	bio := newBaggageInteroperationTest()
+
+	return []mixedAPIsTestCase{
+		{
+			desc:  "simple otel -> ot -> otel",
+			setup: st.setup,
+			run:   st.runOtelOTOtel,
+			check: st.check,
+		},
+		{
+			desc:  "simple ot -> otel -> ot",
+			setup: st.setup,
+			run:   st.runOTOtelOT,
+			check: st.check,
+		},
+		{
+			desc:  "current/active span otel -> ot -> otel",
+			setup: cast.setup,
+			run:   cast.runOtelOTOtel,
+			check: cast.check,
+		},
+		{
+			desc:  "current/active span ot -> otel -> ot",
+			setup: cast.setup,
+			run:   cast.runOTOtelOT,
+			check: cast.check,
+		},
+		{
+			desc:  "context intact otel -> ot -> otel",
+			setup: coin.setup,
+			run:   coin.runOtelOTOtel,
+			check: coin.check,
+		},
+		{
+			desc:  "context intact ot -> otel -> ot",
+			setup: coin.setup,
+			run:   coin.runOTOtelOT,
+			check: coin.check,
+		},
+		{
+			desc:  "baggage items preservation across layers otel -> ot -> otel",
+			setup: bip.setup,
+			run:   bip.runOtelOTOtel,
+			check: bip.check,
+		},
+		{
+			desc:  "baggage items preservation across layers ot -> otel -> ot",
+			setup: bip.setup,
+			run:   bip.runOTOtelOT,
+			check: bip.check,
+		},
+		{
+			desc:  "baggage items interoperation across layers ot -> otel -> ot",
+			setup: bio.setup,
+			run:   bio.runOTOtelOT,
+			check: bio.check,
+		},
+		{
+			desc:  "baggage items interoperation across layers otel -> ot -> otel",
+			setup: bio.setup,
+			run:   bio.runOtelOTOtel,
+			check: bio.check,
+		},
+	}
+}
+
+func TestMixedAPIs(t *testing.T) {
+	for idx, tc := range getMixedAPIsTestCases() {
+		t.Logf("Running test case %d: %s", idx, tc.desc)
+		mockOtelTracer := internal.NewMockTracer()
+		ctx, otTracer, otelProvider := NewTracerPairWithContext(context.Background(), mockOtelTracer)
+		otTracer.SetWarningHandler(func(msg string) {
+			t.Log(msg)
+		})
+
+		otel.SetTracerProvider(otelProvider)
+		ot.SetGlobalTracer(otTracer)
+
+		tc.setup(t, mockOtelTracer)
+		tc.run(t, ctx)
+		tc.check(t, mockOtelTracer)
+	}
+}
+
+// simple test
+
+type simpleTest struct {
+	traceID trace.TraceID
+	spanIDs []trace.SpanID
+}
+
+func newSimpleTest() *simpleTest {
+	return &simpleTest{
+		traceID: simpleTraceID(),
+		spanIDs: simpleSpanIDs(3),
+	}
+}
+
+func (st *simpleTest) setup(t *testing.T, tracer *internal.MockTracer) {
+	tracer.SpareTraceIDs = append(tracer.SpareTraceIDs, st.traceID)
+	tracer.SpareSpanIDs = append(tracer.SpareSpanIDs, st.spanIDs...)
+}
+
+func (st *simpleTest) check(t *testing.T, tracer *internal.MockTracer) {
+	checkTraceAndSpans(t, tracer, st.traceID, st.spanIDs)
+}
+
+func (st *simpleTest) runOtelOTOtel(t *testing.T, ctx context.Context) {
+	runOtelOTOtel(t, ctx, "simple", st.noop)
+}
+
+func (st *simpleTest) runOTOtelOT(t *testing.T, ctx context.Context) {
+	runOTOtelOT(t, ctx, "simple", st.noop)
+}
+
+func (st *simpleTest) noop(t *testing.T, ctx context.Context) context.Context {
+	return ctx
+}
+
+// current/active span test
+
+type currentActiveSpanTest struct {
+	traceID trace.TraceID
+	spanIDs []trace.SpanID
+
+	recordedCurrentOtelSpanIDs []trace.SpanID
+	recordedActiveOTSpanIDs    []trace.SpanID
+}
+
+func newCurrentActiveSpanTest() *currentActiveSpanTest {
+	return &currentActiveSpanTest{
+		traceID: simpleTraceID(),
+		spanIDs: simpleSpanIDs(3),
+	}
+}
+
+func (cast *currentActiveSpanTest) setup(t *testing.T, tracer *internal.MockTracer) {
+	tracer.SpareTraceIDs = append(tracer.SpareTraceIDs, cast.traceID)
+	tracer.SpareSpanIDs = append(tracer.SpareSpanIDs, cast.spanIDs...)
+
+	cast.recordedCurrentOtelSpanIDs = nil
+	cast.recordedActiveOTSpanIDs = nil
+}
+
+func (cast *currentActiveSpanTest) check(t *testing.T, tracer *internal.MockTracer) {
+	checkTraceAndSpans(t, tracer, cast.traceID, cast.spanIDs)
+	if len(cast.recordedCurrentOtelSpanIDs) != len(cast.spanIDs) {
+		t.Errorf("Expected to have %d recorded Otel current spans, got %d", len(cast.spanIDs), len(cast.recordedCurrentOtelSpanIDs))
+	}
+	if len(cast.recordedActiveOTSpanIDs) != len(cast.spanIDs) {
+		t.Errorf("Expected to have %d recorded OT active spans, got %d", len(cast.spanIDs), len(cast.recordedActiveOTSpanIDs))
+	}
+
+	minLen := min(len(cast.recordedCurrentOtelSpanIDs), len(cast.spanIDs))
+	minLen = min(minLen, len(cast.recordedActiveOTSpanIDs))
+	for i := 0; i < minLen; i++ {
+		if cast.recordedCurrentOtelSpanIDs[i] != cast.spanIDs[i] {
+			t.Errorf("Expected span idx %d (%d) to be recorded as current span in Otel, got %d", i, cast.spanIDs[i], cast.recordedCurrentOtelSpanIDs[i])
+		}
+		if cast.recordedActiveOTSpanIDs[i] != cast.spanIDs[i] {
+			t.Errorf("Expected span idx %d (%d) to be recorded as active span in OT, got %d", i, cast.spanIDs[i], cast.recordedActiveOTSpanIDs[i])
+		}
+	}
+}
+
+func (cast *currentActiveSpanTest) runOtelOTOtel(t *testing.T, ctx context.Context) {
+	runOtelOTOtel(t, ctx, "cast", cast.recordSpans)
+}
+
+func (cast *currentActiveSpanTest) runOTOtelOT(t *testing.T, ctx context.Context) {
+	runOTOtelOT(t, ctx, "cast", cast.recordSpans)
+}
+
+func (cast *currentActiveSpanTest) recordSpans(t *testing.T, ctx context.Context) context.Context {
+	spanID := trace.SpanContextFromContext(ctx).SpanID()
+	cast.recordedCurrentOtelSpanIDs = append(cast.recordedCurrentOtelSpanIDs, spanID)
+
+	spanID = trace.SpanID{}
+	if bridgeSpan, ok := ot.SpanFromContext(ctx).(*bridgeSpan); ok {
+		spanID = bridgeSpan.otelSpan.SpanContext().SpanID()
+	}
+	cast.recordedActiveOTSpanIDs = append(cast.recordedActiveOTSpanIDs, spanID)
+	return ctx
+}
+
+// context intact test
+
+type contextIntactTest struct {
+	contextKeyValues []internal.MockContextKeyValue
+
+	recordedContextValues []interface{}
+	recordIdx             int
+}
+
+type coin1Key struct{}
+
+type coin1Value struct{}
+
+type coin2Key struct{}
+
+type coin2Value struct{}
+
+type coin3Key struct{}
+
+type coin3Value struct{}
+
+func newContextIntactTest() *contextIntactTest {
+	return &contextIntactTest{
+		contextKeyValues: []internal.MockContextKeyValue{
+			{
+				Key:   coin1Key{},
+				Value: coin1Value{},
+			},
+			{
+				Key:   coin2Key{},
+				Value: coin2Value{},
+			},
+			{
+				Key:   coin3Key{},
+				Value: coin3Value{},
+			},
+		},
+	}
+}
+
+func (coin *contextIntactTest) setup(t *testing.T, tracer *internal.MockTracer) {
+	tracer.SpareContextKeyValues = append(tracer.SpareContextKeyValues, coin.contextKeyValues...)
+
+	coin.recordedContextValues = nil
+	coin.recordIdx = 0
+}
+
+func (coin *contextIntactTest) check(t *testing.T, tracer *internal.MockTracer) {
+	if len(coin.recordedContextValues) != len(coin.contextKeyValues) {
+		t.Errorf("Expected to have %d recorded context values, got %d", len(coin.contextKeyValues), len(coin.recordedContextValues))
+	}
+
+	minLen := min(len(coin.recordedContextValues), len(coin.contextKeyValues))
+	for i := 0; i < minLen; i++ {
+		key := coin.contextKeyValues[i].Key
+		value := coin.contextKeyValues[i].Value
+		gotValue := coin.recordedContextValues[i]
+		if value != gotValue {
+			t.Errorf("Expected value %#v for key %#v, got %#v", value, key, gotValue)
+		}
+	}
+}
+
+func (coin *contextIntactTest) runOtelOTOtel(t *testing.T, ctx context.Context) {
+	runOtelOTOtel(t, ctx, "coin", coin.recordValue)
+}
+
+func (coin *contextIntactTest) runOTOtelOT(t *testing.T, ctx context.Context) {
+	runOTOtelOT(t, ctx, "coin", coin.recordValue)
+}
+
+func (coin *contextIntactTest) recordValue(t *testing.T, ctx context.Context) context.Context {
+	if coin.recordIdx >= len(coin.contextKeyValues) {
+		t.Errorf("Too many steps?")
+		return ctx
+	}
+	key := coin.contextKeyValues[coin.recordIdx].Key
+	coin.recordIdx++
+	coin.recordedContextValues = append(coin.recordedContextValues, ctx.Value(key))
+	return ctx
+}
+
+// baggage items preservation test
+
+type bipBaggage struct {
+	key   string
+	value string
+}
+
+type baggageItemsPreservationTest struct {
+	baggageItems []bipBaggage
+
+	step            int
+	recordedBaggage []map[string]string
+}
+
+func newBaggageItemsPreservationTest() *baggageItemsPreservationTest {
+	return &baggageItemsPreservationTest{
+		baggageItems: []bipBaggage{
+			{
+				key:   "First",
+				value: "one",
+			},
+			{
+				key:   "Second",
+				value: "two",
+			},
+			{
+				key:   "Third",
+				value: "three",
+			},
+		},
+	}
+}
+
+func (bip *baggageItemsPreservationTest) setup(t *testing.T, tracer *internal.MockTracer) {
+	bip.step = 0
+	bip.recordedBaggage = nil
+}
+
+func (bip *baggageItemsPreservationTest) check(t *testing.T, tracer *internal.MockTracer) {
+	if len(bip.recordedBaggage) != len(bip.baggageItems) {
+		t.Errorf("Expected %d recordings, got %d", len(bip.baggageItems), len(bip.recordedBaggage))
+	}
+	minLen := min(len(bip.recordedBaggage), len(bip.baggageItems))
+
+	for i := 0; i < minLen; i++ {
+		recordedItems := bip.recordedBaggage[i]
+		if len(recordedItems) != i+1 {
+			t.Errorf("Expected %d recorded baggage items in recording %d, got %d", i+1, i+1, len(bip.recordedBaggage[i]))
+		}
+		minItemLen := min(len(bip.baggageItems), i+1)
+		for j := 0; j < minItemLen; j++ {
+			expectedItem := bip.baggageItems[j]
+			if gotValue, ok := recordedItems[expectedItem.key]; !ok {
+				t.Errorf("Missing baggage item %q in recording %d", expectedItem.key, i+1)
+			} else if gotValue != expectedItem.value {
+				t.Errorf("Expected recorded baggage item %q in recording %d + 1to be %q, got %q", expectedItem.key, i, expectedItem.value, gotValue)
+			} else {
+				delete(recordedItems, expectedItem.key)
+			}
+		}
+		for key, value := range recordedItems {
+			t.Errorf("Unexpected baggage item in recording %d: %q -> %q", i+1, key, value)
+		}
+	}
+}
+
+func (bip *baggageItemsPreservationTest) runOtelOTOtel(t *testing.T, ctx context.Context) {
+	runOtelOTOtel(t, ctx, "bip", bip.addAndRecordBaggage)
+}
+
+func (bip *baggageItemsPreservationTest) runOTOtelOT(t *testing.T, ctx context.Context) {
+	runOTOtelOT(t, ctx, "bip", bip.addAndRecordBaggage)
+}
+
+func (bip *baggageItemsPreservationTest) addAndRecordBaggage(t *testing.T, ctx context.Context) context.Context {
+	if bip.step >= len(bip.baggageItems) {
+		t.Errorf("Too many steps?")
+		return ctx
+	}
+	span := ot.SpanFromContext(ctx)
+	if span == nil {
+		t.Errorf("No active OpenTracing span")
+		return ctx
+	}
+	idx := bip.step
+	bip.step++
+	span.SetBaggageItem(bip.baggageItems[idx].key, bip.baggageItems[idx].value)
+	sctx := span.Context()
+	recording := make(map[string]string)
+	sctx.ForeachBaggageItem(func(key, value string) bool {
+		recording[key] = value
+		return true
+	})
+	bip.recordedBaggage = append(bip.recordedBaggage, recording)
+	return ctx
+}
+
+// baggage interoperation test
+
+type baggageInteroperationTest struct {
+	baggageItems []bipBaggage
+
+	step                int
+	recordedOTBaggage   []map[string]string
+	recordedOtelBaggage []map[string]string
+}
+
+func newBaggageInteroperationTest() *baggageInteroperationTest {
+	return &baggageInteroperationTest{
+		baggageItems: []bipBaggage{
+			{
+				key:   "First",
+				value: "one",
+			},
+			{
+				key:   "Second",
+				value: "two",
+			},
+			{
+				key:   "Third",
+				value: "three",
+			},
+		},
+	}
+}
+
+func (bio *baggageInteroperationTest) setup(t *testing.T, tracer *internal.MockTracer) {
+	bio.step = 0
+	bio.recordedOTBaggage = nil
+	bio.recordedOtelBaggage = nil
+}
+
+func (bio *baggageInteroperationTest) check(t *testing.T, tracer *internal.MockTracer) {
+	checkBIORecording(t, "OT", bio.baggageItems, bio.recordedOTBaggage)
+	checkBIORecording(t, "Otel", bio.baggageItems, bio.recordedOtelBaggage)
+}
+
+func checkBIORecording(t *testing.T, apiDesc string, initialItems []bipBaggage, recordings []map[string]string) {
+	// expect recordings count to equal the number of initial
+	// items
+
+	// each recording should have a duplicated item from initial
+	// items, one with OT suffix, another one with Otel suffix
+
+	// expect each subsequent recording to have two more items, up
+	// to double of the count of the initial items
+
+	if len(initialItems) != len(recordings) {
+		t.Errorf("Expected %d recordings from %s, got %d", len(initialItems), apiDesc, len(recordings))
+	}
+	minRecLen := min(len(initialItems), len(recordings))
+	for i := 0; i < minRecLen; i++ {
+		recordedItems := recordings[i]
+		expectedItemsInStep := (i + 1) * 2
+		if expectedItemsInStep != len(recordedItems) {
+			t.Errorf("Expected %d recorded items in recording %d from %s, got %d", expectedItemsInStep, i, apiDesc, len(recordedItems))
+		}
+		recordedItemsCopy := make(map[string]string, len(recordedItems))
+		for k, v := range recordedItems {
+			recordedItemsCopy[k] = v
+		}
+		for j := 0; j < i+1; j++ {
+			otKey, otelKey := generateBaggageKeys(initialItems[j].key)
+			value := initialItems[j].value
+			for _, k := range []string{otKey, otelKey} {
+				if v, ok := recordedItemsCopy[k]; ok {
+					if value != v {
+						t.Errorf("Expected value %s under key %s in recording %d from %s, got %s", value, k, i, apiDesc, v)
+					}
+					delete(recordedItemsCopy, k)
+				} else {
+					t.Errorf("Missing key %s in recording %d from %s", k, i, apiDesc)
+				}
+			}
+		}
+		for k, v := range recordedItemsCopy {
+			t.Errorf("Unexpected key-value pair %s = %s in recording %d from %s", k, v, i, apiDesc)
+		}
+	}
+}
+
+func (bio *baggageInteroperationTest) runOtelOTOtel(t *testing.T, ctx context.Context) {
+	runOtelOTOtel(t, ctx, "bio", bio.addAndRecordBaggage)
+}
+
+func (bio *baggageInteroperationTest) runOTOtelOT(t *testing.T, ctx context.Context) {
+	runOTOtelOT(t, ctx, "bio", bio.addAndRecordBaggage)
+}
+
+func (bio *baggageInteroperationTest) addAndRecordBaggage(t *testing.T, ctx context.Context) context.Context {
+	if bio.step >= len(bio.baggageItems) {
+		t.Errorf("Too many steps?")
+		return ctx
+	}
+	otSpan := ot.SpanFromContext(ctx)
+	if otSpan == nil {
+		t.Errorf("No active OpenTracing span")
+		return ctx
+	}
+	idx := bio.step
+	bio.step++
+	key := bio.baggageItems[idx].key
+	otKey, otelKey := generateBaggageKeys(key)
+	value := bio.baggageItems[idx].value
+
+	otSpan.SetBaggageItem(otKey, value)
+
+	m, err := baggage.NewMember(otelKey, value)
+	if err != nil {
+		t.Error(err)
+		return ctx
+	}
+	b, err := baggage.FromContext(ctx).SetMember(m)
+	if err != nil {
+		t.Error(err)
+		return ctx
+	}
+	ctx = baggage.ContextWithBaggage(ctx, b)
+
+	otRecording := make(map[string]string)
+	otSpan.Context().ForeachBaggageItem(func(key, value string) bool {
+		otRecording[key] = value
+		return true
+	})
+	otelRecording := make(map[string]string)
+	for _, m := range baggage.FromContext(ctx).Members() {
+		otelRecording[m.Key()] = m.Value()
+	}
+	bio.recordedOTBaggage = append(bio.recordedOTBaggage, otRecording)
+	bio.recordedOtelBaggage = append(bio.recordedOtelBaggage, otelRecording)
+	return ctx
+}
+
+func generateBaggageKeys(key string) (otKey, otelKey string) {
+	otKey, otelKey = key+"-Ot", key+"-Otel"
+	return
+}
+
+// helpers
+
+func checkTraceAndSpans(t *testing.T, tracer *internal.MockTracer, expectedTraceID trace.TraceID, expectedSpanIDs []trace.SpanID) {
+	expectedSpanCount := len(expectedSpanIDs)
+
+	// reverse spanIDs, since first span ID belongs to root, that
+	// finishes last
+	spanIDs := make([]trace.SpanID, len(expectedSpanIDs))
+	copy(spanIDs, expectedSpanIDs)
+	reverse(len(spanIDs), func(i, j int) {
+		spanIDs[i], spanIDs[j] = spanIDs[j], spanIDs[i]
+	})
+	// the last finished span has no parent
+	parentSpanIDs := append(spanIDs[1:], trace.SpanID{})
+
+	sks := map[trace.SpanID]trace.SpanKind{
+		{125}: trace.SpanKindProducer,
+		{124}: trace.SpanKindInternal,
+		{123}: trace.SpanKindClient,
+	}
+
+	if len(tracer.FinishedSpans) != expectedSpanCount {
+		t.Errorf("Expected %d finished spans, got %d", expectedSpanCount, len(tracer.FinishedSpans))
+	}
+	for idx, span := range tracer.FinishedSpans {
+		sctx := span.SpanContext()
+		if sctx.TraceID() != expectedTraceID {
+			t.Errorf("Expected trace ID %v in span %d (%d), got %v", expectedTraceID, idx, sctx.SpanID(), sctx.TraceID())
+		}
+		expectedSpanID := spanIDs[idx]
+		expectedParentSpanID := parentSpanIDs[idx]
+		if sctx.SpanID() != expectedSpanID {
+			t.Errorf("Expected finished span %d to have span ID %d, but got %d", idx, expectedSpanID, sctx.SpanID())
+		}
+		if span.ParentSpanID != expectedParentSpanID {
+			t.Errorf("Expected finished span %d (span ID: %d) to have parent span ID %d, but got %d", idx, sctx.SpanID(), expectedParentSpanID, span.ParentSpanID)
+		}
+		if span.SpanKind != sks[span.SpanContext().SpanID()] {
+			t.Errorf("Expected finished span %d (span ID: %d) to have span.kind to be '%v' but was '%v'", idx, sctx.SpanID(), sks[span.SpanContext().SpanID()], span.SpanKind)
+		}
+	}
+}
+
+func reverse(length int, swap func(i, j int)) {
+	for left, right := 0, length-1; left < right; left, right = left+1, right-1 {
+		swap(left, right)
+	}
+}
+
+func simpleTraceID() trace.TraceID {
+	return [16]byte{123, 42}
+}
+
+func simpleSpanIDs(count int) []trace.SpanID {
+	base := []trace.SpanID{
+		{123},
+		{124},
+		{125},
+		{126},
+		{127},
+		{128},
+	}
+	return base[:count]
+}
+
+func min(a, b int) int {
+	if a > b {
+		return b
+	}
+	return a
+}
+
+func runOtelOTOtel(t *testing.T, ctx context.Context, name string, callback func(*testing.T, context.Context) context.Context) {
+	tr := otel.Tracer("")
+	ctx, span := tr.Start(ctx, fmt.Sprintf("%s_Otel_OTOtel", name), trace.WithSpanKind(trace.SpanKindClient))
+	defer span.End()
+	ctx = callback(t, ctx)
+	func(ctx2 context.Context) {
+		span, ctx2 := ot.StartSpanFromContext(ctx2, fmt.Sprintf("%sOtel_OT_Otel", name))
+		defer span.Finish()
+		ctx2 = callback(t, ctx2)
+		func(ctx3 context.Context) {
+			ctx3, span := tr.Start(ctx3, fmt.Sprintf("%sOtelOT_Otel_", name), trace.WithSpanKind(trace.SpanKindProducer))
+			defer span.End()
+			_ = callback(t, ctx3)
+		}(ctx2)
+	}(ctx)
+}
+
+func runOTOtelOT(t *testing.T, ctx context.Context, name string, callback func(*testing.T, context.Context) context.Context) {
+	tr := otel.Tracer("")
+	span, ctx := ot.StartSpanFromContext(ctx, fmt.Sprintf("%s_OT_OtelOT", name), ot.Tag{Key: "span.kind", Value: "client"})
+	defer span.Finish()
+	ctx = callback(t, ctx)
+	func(ctx2 context.Context) {
+		ctx2, span := tr.Start(ctx2, fmt.Sprintf("%sOT_Otel_OT", name))
+		defer span.End()
+		ctx2 = callback(t, ctx2)
+		func(ctx3 context.Context) {
+			span, ctx3 := ot.StartSpanFromContext(ctx3, fmt.Sprintf("%sOTOtel_OT_", name), ot.Tag{Key: "span.kind", Value: "producer"})
+			defer span.Finish()
+			_ = callback(t, ctx3)
+		}(ctx2)
+	}(ctx)
+}
+
+func TestOtTagToOTelAttrCheckTypeConversions(t *testing.T) {
+	tableTest := []struct {
+		key               string
+		value             interface{}
+		expectedValueType attribute.Type
+	}{
+		{
+			key:               "bool to bool",
+			value:             true,
+			expectedValueType: attribute.BOOL,
+		},
+		{
+			key:               "int to int64",
+			value:             123,
+			expectedValueType: attribute.INT64,
+		},
+		{
+			key:               "uint to string",
+			value:             uint(1234),
+			expectedValueType: attribute.STRING,
+		},
+		{
+			key:               "int32 to int64",
+			value:             int32(12345),
+			expectedValueType: attribute.INT64,
+		},
+		{
+			key:               "uint32 to int64",
+			value:             uint32(123456),
+			expectedValueType: attribute.INT64,
+		},
+		{
+			key:               "int64 to int64",
+			value:             int64(1234567),
+			expectedValueType: attribute.INT64,
+		},
+		{
+			key:               "uint64 to string",
+			value:             uint64(12345678),
+			expectedValueType: attribute.STRING,
+		},
+		{
+			key:               "float32 to float64",
+			value:             float32(3.14),
+			expectedValueType: attribute.FLOAT64,
+		},
+		{
+			key:               "float64 to float64",
+			value:             float64(3.14),
+			expectedValueType: attribute.FLOAT64,
+		},
+		{
+			key:               "string to string",
+			value:             "string_value",
+			expectedValueType: attribute.STRING,
+		},
+		{
+			key:               "unexpected type to string",
+			value:             struct{}{},
+			expectedValueType: attribute.STRING,
+		},
+	}
+
+	for _, test := range tableTest {
+		got := otTagToOTelAttr(test.key, test.value)
+		if test.expectedValueType != got.Value.Type() {
+			t.Errorf("Expected type %s, but got %s after conversion '%v' value",
+				test.expectedValueType,
+				got.Value.Type(),
+				test.value)
+		}
+	}
+}

+ 71 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/provider.go

@@ -0,0 +1,71 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opentracing // import "go.opentelemetry.io/otel/bridge/opentracing"
+
+import (
+	"sync"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+// TracerProvider is an OpenTelemetry TracerProvider that wraps an OpenTracing
+// Tracer.
+type TracerProvider struct {
+	bridge   *BridgeTracer
+	provider trace.TracerProvider
+
+	tracers map[wrappedTracerKey]*WrapperTracer
+	mtx     sync.Mutex
+}
+
+var _ trace.TracerProvider = (*TracerProvider)(nil)
+
+// NewTracerProvider returns a new TracerProvider that creates new instances of
+// WrapperTracer from the given TracerProvider.
+func NewTracerProvider(bridge *BridgeTracer, provider trace.TracerProvider) *TracerProvider {
+	return &TracerProvider{
+		bridge:   bridge,
+		provider: provider,
+
+		tracers: make(map[wrappedTracerKey]*WrapperTracer),
+	}
+}
+
+type wrappedTracerKey struct {
+	name    string
+	version string
+}
+
+// Tracer creates a WrappedTracer that wraps the OpenTelemetry tracer for each call to
+// Tracer(). Repeated calls to Tracer() with the same configuration will look up and
+// return an existing instance of WrapperTracer.
+func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
+	p.mtx.Lock()
+	defer p.mtx.Unlock()
+
+	c := trace.NewTracerConfig(opts...)
+	key := wrappedTracerKey{
+		name:    name,
+		version: c.InstrumentationVersion(),
+	}
+
+	if t, ok := p.tracers[key]; ok {
+		return t
+	}
+
+	wrapper := NewWrapperTracer(p.bridge, p.provider.Tracer(name, opts...))
+	p.tracers[key] = wrapper
+	return wrapper
+}

+ 85 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/provider_test.go

@@ -0,0 +1,85 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opentracing
+
+import (
+	"testing"
+
+	"go.opentelemetry.io/otel/bridge/opentracing/internal"
+	"go.opentelemetry.io/otel/trace"
+)
+
+type namedMockTracer struct {
+	name string
+	*internal.MockTracer
+}
+
+type namedMockTracerProvider struct{}
+
+var _ trace.TracerProvider = (*namedMockTracerProvider)(nil)
+
+// Tracer returns the WrapperTracer associated with the WrapperTracerProvider.
+func (p *namedMockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
+	return &namedMockTracer{
+		name:       name,
+		MockTracer: internal.NewMockTracer(),
+	}
+}
+
+func TestTracerProvider(t *testing.T) {
+	// assertMockTracerName casts tracer into a named mock tracer provided by
+	// namedMockTracerProvider, and asserts against its name
+	assertMockTracerName := func(t *testing.T, tracer trace.Tracer, name string) {
+		// Unwrap the tracer
+		wrapped := tracer.(*WrapperTracer)
+		tracer = wrapped.tracer
+
+		// Cast into the underlying type and assert
+		if mock, ok := tracer.(*namedMockTracer); ok {
+			if name != mock.name {
+				t.Errorf("expected name %q, got %q", name, mock.name)
+			}
+		} else if !ok {
+			t.Errorf("expected *namedMockTracer, got %T", mock)
+		}
+	}
+
+	var (
+		foobar   = "foobar"
+		bazbar   = "bazbar"
+		provider = NewTracerProvider(nil, &namedMockTracerProvider{})
+	)
+
+	t.Run("Tracers should be created with foobar from provider", func(t *testing.T) {
+		tracer := provider.Tracer(foobar)
+		assertMockTracerName(t, tracer, foobar)
+	})
+
+	t.Run("Repeated requests to create a tracer should provide the existing tracer", func(t *testing.T) {
+		tracer1 := provider.Tracer(foobar)
+		assertMockTracerName(t, tracer1, foobar)
+		tracer2 := provider.Tracer(foobar)
+		assertMockTracerName(t, tracer2, foobar)
+		tracer3 := provider.Tracer(bazbar)
+		assertMockTracerName(t, tracer3, bazbar)
+
+		if tracer1 != tracer2 {
+			t.Errorf("expected the same tracer, got different tracers")
+		}
+		if tracer1 == tracer3 || tracer2 == tracer3 {
+			t.Errorf("expected different tracers, got the same tracer")
+		}
+	})
+}

+ 99 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/test/bridge_grpc_test.go

@@ -0,0 +1,99 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package test
+
+import (
+	"context"
+	"net"
+	"testing"
+	"time"
+
+	otgrpc "github.com/opentracing-contrib/go-grpc"
+	testpb "github.com/opentracing-contrib/go-grpc/test/otgrpc_testing"
+	ot "github.com/opentracing/opentracing-go"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+
+	ototel "go.opentelemetry.io/otel/bridge/opentracing"
+	"go.opentelemetry.io/otel/bridge/opentracing/internal"
+	"go.opentelemetry.io/otel/propagation"
+)
+
+type testGRPCServer struct{}
+
+func (*testGRPCServer) UnaryCall(ctx context.Context, r *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
+	return &testpb.SimpleResponse{Payload: r.Payload * 2}, nil
+}
+func (*testGRPCServer) StreamingOutputCall(*testpb.SimpleRequest, testpb.TestService_StreamingOutputCallServer) error {
+	return nil
+}
+func (*testGRPCServer) StreamingInputCall(testpb.TestService_StreamingInputCallServer) error {
+	return nil
+}
+func (*testGRPCServer) StreamingBidirectionalCall(testpb.TestService_StreamingBidirectionalCallServer) error {
+	return nil
+}
+
+func startTestGRPCServer(t *testing.T, tracer ot.Tracer) (*grpc.Server, net.Addr) {
+	lis, _ := net.Listen("tcp", ":0")
+	server := grpc.NewServer(
+		grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer)),
+	)
+	testpb.RegisterTestServiceServer(server, &testGRPCServer{})
+
+	go func() {
+		err := server.Serve(lis)
+		require.NoError(t, err)
+	}()
+
+	return server, lis.Addr()
+}
+
+func TestBridgeTracer_ExtractAndInject_gRPC(t *testing.T) {
+	tracer := internal.NewMockTracer()
+
+	bridge := ototel.NewBridgeTracer()
+	bridge.SetOpenTelemetryTracer(tracer)
+	bridge.SetTextMapPropagator(propagation.TraceContext{})
+
+	srv, addr := startTestGRPCServer(t, bridge)
+	defer srv.Stop()
+
+	conn, err := grpc.Dial(
+		addr.String(),
+		grpc.WithTransportCredentials(insecure.NewCredentials()),
+		grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(bridge)),
+	)
+	require.NoError(t, err)
+	cli := testpb.NewTestServiceClient(conn)
+
+	ctx, cx := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cx()
+	res, err := cli.UnaryCall(ctx, &testpb.SimpleRequest{Payload: 42})
+	require.NoError(t, err)
+	assert.EqualValues(t, 84, res.Payload)
+
+	checkSpans := func() bool {
+		return len(tracer.FinishedSpans) == 2
+	}
+	require.Eventuallyf(t, checkSpans, 5*time.Second, 5*time.Millisecond, "expecting two spans")
+	assert.Equal(t,
+		tracer.FinishedSpans[0].SpanContext().TraceID(),
+		tracer.FinishedSpans[1].SpanContext().TraceID(),
+		"expecting same trace ID",
+	)
+}

+ 36 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/test/go.mod

@@ -0,0 +1,36 @@
+module go.opentelemetry.io/otel/bridge/opentracing/test
+
+go 1.20
+
+replace go.opentelemetry.io/otel => ../../..
+
+replace go.opentelemetry.io/otel/bridge/opentracing => ../
+
+replace go.opentelemetry.io/otel/trace => ../../../trace
+
+require (
+	github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e
+	github.com/opentracing/opentracing-go v1.2.0
+	github.com/stretchr/testify v1.8.4
+	go.opentelemetry.io/otel v1.19.0
+	go.opentelemetry.io/otel/bridge/opentracing v1.19.0
+	google.golang.org/grpc v1.58.2
+)
+
+require (
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/go-logr/logr v1.2.4 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	go.opentelemetry.io/otel/metric v1.19.0 // indirect
+	go.opentelemetry.io/otel/trace v1.19.0 // indirect
+	golang.org/x/net v0.12.0 // indirect
+	golang.org/x/sys v0.12.0 // indirect
+	golang.org/x/text v0.11.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
+	google.golang.org/protobuf v1.31.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
+
+replace go.opentelemetry.io/otel/metric => ../../../metric

+ 68 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/test/go.sum

@@ -0,0 +1,68 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
+github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg=
+github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
+golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
+golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
+google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 43 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/util.go

@@ -0,0 +1,43 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opentracing // import "go.opentelemetry.io/otel/bridge/opentracing"
+
+import (
+	"context"
+
+	"go.opentelemetry.io/otel/trace"
+)
+
+// NewTracerPair is a utility function that creates a BridgeTracer and a
+// WrapperTracerProvider. WrapperTracerProvider creates a single instance of
+// WrapperTracer. The BridgeTracer forwards the calls to the WrapperTracer
+// that wraps the passed tracer. BridgeTracer and WrapperTracerProvider are
+// returned to the caller and the caller is expected to register BridgeTracer
+// with opentracing and WrapperTracerProvider with opentelemetry.
+func NewTracerPair(tracer trace.Tracer) (*BridgeTracer, *WrapperTracerProvider) {
+	bridgeTracer := NewBridgeTracer()
+	wrapperProvider := NewWrappedTracerProvider(bridgeTracer, tracer)
+	bridgeTracer.SetOpenTelemetryTracer(wrapperProvider.Tracer(""))
+	return bridgeTracer, wrapperProvider
+}
+
+// NewTracerPairWithContext is a convenience function. It calls NewTracerPair
+// and returns a hooked version of ctx with the created BridgeTracer along
+// with the BridgeTracer and WrapperTracerProvider.
+func NewTracerPairWithContext(ctx context.Context, tracer trace.Tracer) (context.Context, *BridgeTracer, *WrapperTracerProvider) {
+	bridgeTracer, wrapperProvider := NewTracerPair(tracer)
+	ctx = bridgeTracer.NewHookedContext(ctx)
+	return ctx, bridgeTracer, wrapperProvider
+}

+ 104 - 0
pkg/go.opentelemetry.io/otel/bridge/opentracing/wrapper.go

@@ -0,0 +1,104 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package opentracing // import "go.opentelemetry.io/otel/bridge/opentracing"
+
+import (
+	"context"
+
+	"go.opentelemetry.io/otel/bridge/opentracing/migration"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// WrapperTracerProvider is an OpenTelemetry TracerProvider that wraps an
+// OpenTracing Tracer, created by the deprecated NewWrappedTracerProvider.
+//
+// Deprecated: Use the TracerProvider from NewTracerProvider(...) instead.
+type WrapperTracerProvider struct {
+	wTracer *WrapperTracer
+}
+
+var _ trace.TracerProvider = (*WrapperTracerProvider)(nil)
+
+// Tracer returns the WrapperTracer associated with the WrapperTracerProvider.
+func (p *WrapperTracerProvider) Tracer(_ string, _ ...trace.TracerOption) trace.Tracer {
+	return p.wTracer
+}
+
+// NewWrappedTracerProvider creates a new trace provider that creates a single
+// instance of WrapperTracer that wraps OpenTelemetry tracer, and always returns
+// it unmodified from Tracer().
+//
+// Deprecated: Use NewTracerProvider(...) instead.
+func NewWrappedTracerProvider(bridge *BridgeTracer, tracer trace.Tracer) *WrapperTracerProvider {
+	return &WrapperTracerProvider{
+		wTracer: NewWrapperTracer(bridge, tracer),
+	}
+}
+
+// WrapperTracer is a wrapper around an OpenTelemetry tracer. It
+// mostly forwards the calls to the wrapped tracer, but also does some
+// extra steps like setting up a context with the active OpenTracing
+// span.
+//
+// It does not need to be used when the OpenTelemetry tracer is also
+// aware how to operate in environment where OpenTracing API is also
+// used.
+type WrapperTracer struct {
+	bridge *BridgeTracer
+	tracer trace.Tracer
+}
+
+var _ trace.Tracer = &WrapperTracer{}
+var _ migration.DeferredContextSetupTracerExtension = &WrapperTracer{}
+
+// NewWrapperTracer wraps the passed tracer and also talks to the
+// passed bridge tracer when setting up the context with the new
+// active OpenTracing span.
+func NewWrapperTracer(bridge *BridgeTracer, tracer trace.Tracer) *WrapperTracer {
+	return &WrapperTracer{
+		bridge: bridge,
+		tracer: tracer,
+	}
+}
+
+func (t *WrapperTracer) otelTracer() trace.Tracer {
+	return t.tracer
+}
+
+// Start forwards the call to the wrapped tracer. It also tries to
+// override the tracer of the returned span if the span implements the
+// OverrideTracerSpanExtension interface.
+func (t *WrapperTracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
+	ctx, span := t.otelTracer().Start(ctx, name, opts...)
+	if spanWithExtension, ok := span.(migration.OverrideTracerSpanExtension); ok {
+		spanWithExtension.OverrideTracer(t)
+	}
+	if !migration.SkipContextSetup(ctx) {
+		ctx = t.bridge.ContextWithBridgeSpan(ctx, span)
+	}
+	return ctx, span
+}
+
+// DeferredContextSetupHook is a part of the implementation of the
+// DeferredContextSetupTracerExtension interface. It will try to
+// forward the call to the wrapped tracer if it implements the
+// interface.
+func (t *WrapperTracer) DeferredContextSetupHook(ctx context.Context, span trace.Span) context.Context {
+	if tracerWithExtension, ok := t.otelTracer().(migration.DeferredContextSetupTracerExtension); ok {
+		ctx = tracerWithExtension.DeferredContextSetupHook(ctx, span)
+	}
+	ctx = trace.ContextWithSpan(ctx, span)
+	return ctx
+}

+ 116 - 0
pkg/go.opentelemetry.io/otel/codes/codes.go

@@ -0,0 +1,116 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package codes // import "go.opentelemetry.io/otel/codes"
+
+import (
+	"encoding/json"
+	"fmt"
+	"strconv"
+)
+
+const (
+	// Unset is the default status code.
+	Unset Code = 0
+
+	// Error indicates the operation contains an error.
+	//
+	// NOTE: The error code in OTLP is 2.
+	// The value of this enum is only relevant to the internals
+	// of the Go SDK.
+	Error Code = 1
+
+	// Ok indicates operation has been validated by an Application developers
+	// or Operator to have completed successfully, or contain no error.
+	//
+	// NOTE: The Ok code in OTLP is 1.
+	// The value of this enum is only relevant to the internals
+	// of the Go SDK.
+	Ok Code = 2
+
+	maxCode = 3
+)
+
+// Code is an 32-bit representation of a status state.
+type Code uint32
+
+var codeToStr = map[Code]string{
+	Unset: "Unset",
+	Error: "Error",
+	Ok:    "Ok",
+}
+
+var strToCode = map[string]Code{
+	`"Unset"`: Unset,
+	`"Error"`: Error,
+	`"Ok"`:    Ok,
+}
+
+// String returns the Code as a string.
+func (c Code) String() string {
+	return codeToStr[c]
+}
+
+// UnmarshalJSON unmarshals b into the Code.
+//
+// This is based on the functionality in the gRPC codes package:
+// https://github.com/grpc/grpc-go/blob/bb64fee312b46ebee26be43364a7a966033521b1/codes/codes.go#L218-L244
+func (c *Code) UnmarshalJSON(b []byte) error {
+	// From json.Unmarshaler: By convention, to approximate the behavior of
+	// Unmarshal itself, Unmarshalers implement UnmarshalJSON([]byte("null")) as
+	// a no-op.
+	if string(b) == "null" {
+		return nil
+	}
+	if c == nil {
+		return fmt.Errorf("nil receiver passed to UnmarshalJSON")
+	}
+
+	var x interface{}
+	if err := json.Unmarshal(b, &x); err != nil {
+		return err
+	}
+	switch x.(type) {
+	case string:
+		if jc, ok := strToCode[string(b)]; ok {
+			*c = jc
+			return nil
+		}
+		return fmt.Errorf("invalid code: %q", string(b))
+	case float64:
+		if ci, err := strconv.ParseUint(string(b), 10, 32); err == nil {
+			if ci >= maxCode {
+				return fmt.Errorf("invalid code: %q", ci)
+			}
+
+			*c = Code(ci)
+			return nil
+		}
+		return fmt.Errorf("invalid code: %q", string(b))
+	default:
+		return fmt.Errorf("invalid code: %q", string(b))
+	}
+}
+
+// MarshalJSON returns c as the JSON encoding of c.
+func (c *Code) MarshalJSON() ([]byte, error) {
+	if c == nil {
+		return []byte("null"), nil
+	}
+	str, ok := codeToStr[*c]
+	if !ok {
+		return nil, fmt.Errorf("invalid code: %d", *c)
+	}
+	return []byte(fmt.Sprintf("%q", str)), nil
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов