# Contributing to opentelemetry-rust

The Rust special interest group (SIG) meets on alternating weeks between Tuesday
at 9:00 AM PT and Wednesday at 8:00 AM PT. The meeting is subject to change
depending on contributors' availability. Check the [OpenTelemetry community
calendar](https://github.com/open-telemetry/community?tab=readme-ov-file#calendar)
for specific dates and for Zoom meeting links. "OTel Rust SIG" is the name of
meeting for this group.

Meeting notes are available as a public [Google
doc](https://docs.google.com/document/d/12upOzNk8c3SFTjsL6IRohCWMgzLKoknSCOOdMakbWo4/edit).
If you have trouble accessing the doc, please get in touch on
[Slack](https://cloud-native.slack.com/archives/C03GDP0H023).

The meeting is open for all to join. We invite everyone to join our meeting,
regardless of your experience level. Whether you're a seasoned OpenTelemetry
developer, just starting your journey, or simply curious about the work we do,
you're more than welcome to participate!

Even though, anybody can contribute, there are benefits of being a member of our
community. See to the [community membership
document](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md)
on how to become a
[**Member**](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#member),
[**Approver**](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver)
and
[**Maintainer**](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).

## Pull Requests

### Before You Start

If you'd like to work on something that isn't already tracked as an issue —
whether it's a new feature, enhancement, or significant refactor — please
[create an issue](https://github.com/open-telemetry/opentelemetry-rust/issues/new)
first and describe your proposal. This gives maintainers a chance to provide
feedback on the approach before you invest significant time, and helps avoid
situations where a PR doesn't align with the project's direction.

For bug fixes or small improvements to existing functionality, opening a PR
directly is fine.

If you're new to the codebase, these docs will help you get oriented:

- [Architecture overview](docs/design/architecture.md) — workspace structure,
  API/SDK separation, and crate responsibilities
- Signal-specific design docs:
  [traces](docs/design/traces.md),
  [metrics](docs/design/metrics.md),
  [logs](docs/design/logs.md)
- [Architectural decision records](docs/adr/) — context behind past design
  choices
- [Library guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/library-guidelines.md)
  from the OpenTelemetry specification

### Prerequisites

Crate `opentelemetry-otlp` uses gRPC + Protocol Buffers.
You can provide the protocol compiler protoc path programmatically (only works with tonic) or build it from source

```sh
export PROTOC=$(which protoc)
```

It is recommended to use "3.15" or newer of protoc, as some of the proto
definitions include "optional" fields, that are not supported in older versions,
resulting in errors as shown
[here](https://github.com/open-telemetry/opentelemetry-proto/issues/451).

Prerequisites to build the protocol compiler protoc from source

- [protoc](https://github.com/protocolbuffers/protobuf)
- [cmake](https://cmake.org)
- [llvm](https://releases.llvm.org/download.html) (and `LIBCLANG_PATH` environment variable pointing to the `bin` directory of LLVM install)

### How to Send Pull Requests

Everyone is welcome to contribute code to `opentelemetry-rust` via
GitHub pull requests (PRs).

```sh
git clone --recurse-submodule https://github.com/open-telemetry/opentelemetry-rust
```

Enter the newly created directory and add your fork as a new remote:

```sh
git remote add <YOUR_FORK> git@github.com:<YOUR_GITHUB_USERNAME>/opentelemetry-rust
```

Check out a new branch, make modifications, run linters and tests, and
push the branch to your fork:

```sh
$ git checkout -b <YOUR_BRANCH_NAME>
# edit files
$ git add -p
$ git commit
$ git push <YOUR_FORK> <YOUR_BRANCH_NAME>
```

Open a pull request against the main
[opentelemetry-rust](https://github.com/open-telemetry/opentelemetry-rust)
repo.

Your pull request should be named according to the
[conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standard. This ensures that
when the PR is squashed into `main`, the resulting commit message is consistent and makes it easier
for us to generate a changelog  standard. 

> **Note**
> It is recommended to run [pre-commit script](scripts/precommit.sh) to catch any issues locally.

### How to Receive Comments

- If the PR is not ready for review, please put `[WIP]` in the title or mark it
  as [`draft`](https://github.blog/2019-02-14-introducing-draft-pull-requests/).
- Make sure CLA is signed and all required CI checks are clear.
- Submit small, focused PRs addressing a single concern/issue.
- Make sure the PR title reflects the contribution.
- Write a summary that helps understand the change.
- Include usage examples in the summary, where applicable.
- Include benchmarks (before/after) in the summary, for contributions that are
  performance enhancements.

### Pull Request Size and Scope

We recommend keeping PRs under 500 lines (excluding `Cargo.lock` and generated
code) to allow thorough and timely reviews. If your change is larger than this,
consider breaking it into incremental PRs — for example:

1. **First PR**: Introduce new types, traits, or structural scaffolding.
2. **Follow-up PRs**: Add the implementation, split further if needed.
3. **Final PR**: Wire everything together and update documentation.

For changes that span multiple signals (traces, metrics, logs), consider
starting with a PR that targets just one signal. This lets maintainers review
the approach on a smaller surface area and give feedback before you replicate
it across all three.

Refactoring must be in its own PR with no behavior changes. Mixing refactoring
with new functionality makes it difficult for reviewers to verify correctness
and often leads to longer review cycles.

### How to Get PRs Merged

A PR is considered to be **ready to merge** when:

- It has received approval from
  [Approvers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver).
  /
  [Maintainers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
- Major feedbacks are resolved.

Any Maintainer can merge the PR once it is **ready to merge**. Note, that some
PRs may not be merged immediately if the repo is in the process of a release and
the maintainers decided to defer the PR to the next release train. Also,
maintainers may decide to wait for more than one approval for certain PRs,
particularly ones that are affecting multiple areas, or topics that may warrant
more discussion.

## Issue Lifecycle and Labels

We use GitHub labels to track issue status and help contributors find work.
Understanding these labels will help you know which issues are ready to be
worked on and how to find ones that match your experience level.

### Filing Issues

When creating a new issue, please use one of the provided
[issue templates](https://github.com/open-telemetry/opentelemetry-rust/issues/new/choose)
(Bug Report or Feature Request). The templates automatically apply triage
labels so that maintainers can find and review new issues. Avoid creating
blank issues, as they won't have the correct labels and may be overlooked.

### Triage

Every new issue filed through a template starts with `triage:todo`. Maintainers
review these and either:

- **`triage:accepted`** — the issue has been reviewed and is ready to be worked
  on. If you're looking for something to contribute, start here.
- **`triage:needmoreinfo`** — the issue needs clarification from the reporter
  before it can be acted on.

**Don't start work on an issue that hasn't been triaged.** An issue with
`triage:todo` may be a duplicate, out of scope, or need a different approach
than what's described. Wait for `triage:accepted` or ask in the issue if you're
interested.

### Finding Work

- **`good first issue`** — scoped issues suitable for newcomers to the
  codebase. These are a starting point, not a restriction — newcomers are
  welcome to work on any accepted issue.
- **`help wanted`** — issues where maintainers welcome contributions and will
  provide extra guidance.

### Area Labels

These indicate which part of the codebase an issue relates to:

| Label | Area |
|---|---|
| `A-trace` | Tracing signal |
| `A-metrics` | Metrics signal |
| `A-log` | Logs signal |
| `A-common` | Cross-cutting / not signal-specific |

### Module Labels

These indicate which crate is affected:

| Label | Crate |
|---|---|
| `M-api` | `opentelemetry` (API) |
| `M-sdk` | `opentelemetry-sdk` |
| `M-exporter-otlp` | `opentelemetry-otlp` |
| `M-exporter-prometheus` | `opentelemetry-prometheus` |
| `M-exporter-zipkin` | `opentelemetry-zipkin` |

### Priority

| Label | Meaning |
|---|---|
| `priority:p0` | Critical stop-the-world issues. Drop everything. |
| `priority:p1` | High priority — should be addressed soon. |
| `priority:p2` | Medium priority. |
| `priority:p3` | Low priority — nice to have. |

### Versioning

These labels are applied to PRs to indicate their semver impact:

| Label | Impact |
|---|---|
| `version:breaking` | Breaking change (major version bump) |
| `version:minor` | New functionality (minor version bump) |
| `version:patch` | Bug fix (patch version bump) |

### Other Labels

| Label | Meaning |
|---|---|
| `S-blocked-spec` | Blocked on an unresolved spec issue |
| `platform:windows` / `platform:linux` / `platform:mac` / `platform:wasm` | Platform-specific |
| `performance` | Performance-related |
| `documentation/examples` | Documentation or examples improvement |

## Design Choices

As with other OpenTelemetry clients, opentelemetry-rust follows the
[opentelemetry-specification](https://github.com/open-telemetry/opentelemetry-specification).

It's especially valuable to read through the [library
guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/library-guidelines.md).

### 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:
<https://github.com/open-telemetry/opentelemetry-specification/issues/165>

### Error Handling

Currently, the Opentelemetry Rust SDK has two ways to handle errors. In the situation where errors are not allowed to return. One should call global error handler to process the errors. Otherwise, one should return the errors.

The Opentelemetry Rust SDK comes with an error type `opentelemetry::Error`. For different function, one error has been defined. All error returned by trace module MUST be wrapped in `opentelemetry::trace::TraceError`. All errors returned by metrics module MUST be wrapped in `opentelemetry::metrics::MetricError`. All errors returned by logs module MUST be wrapped in `opentelemetry::logs::LogsError`.

For users that want to implement their own exporters. It's RECOMMENDED to wrap all errors from the exporter into a crate-level error type, and implement `ExporterError` trait.

### Priority of configurations

OpenTelemetry supports multiple ways to configure the API, SDK and other components. The priority of configurations is as follows:

- Environment variables
- Compiling time configurations provided in the source code

### Experimental/Unstable features

Use `otel_unstable` feature flag for implementation of specification with [experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.27.0/specification/document-status.md) status. This approach ensures clear demarcation and safe integration of new or evolving features. Utilize the following structure:

```rust
#[cfg(feature = "otel_unstable")]
{
    // Your feature implementation
}
```

It's important to regularly review and remove the `otel_unstable` flag from the code once the feature becomes stable. This cleanup process is crucial to maintain the overall code quality and to ensure that stable features are accurately reflected in the main build.

### Optional features

The potential features include:

- Stable and non-experimental features that are compliant with the specification and have a feature flag to minimize compilation size. Example: feature flags for signals (like `logs`, `traces`, `metrics`) and runtimes (`rt-tokio`, `rt-tokio-current-thread`).
- Stable and non-experimental features, although not part of the specification, are crucial for enhancing the tracing/log crate's functionality or boosting performance. These features are also subject to discussion and approval by the OpenTelemetry Rust Maintainers.

All such features should adhere to naming convention  `<signal>_<feature_name>`

## Style Guide

- Run `cargo clippy --all` - this will catch common mistakes and improve
your Rust code
- Run `cargo fmt` - this will find and fix code formatting
issues.

## Testing and Benchmarking

- Run `cargo test --all` - this will execute code and doc tests for all
projects in this workspace.
- Run `cargo bench` - this will run benchmarks to show performance
regressions

Benchmarks are run daily against `main` and results are tracked over time.
The continuous benchmark dashboard is published at
<https://open-telemetry.github.io/opentelemetry-rust/dev/bench/>.
PRs with the `performance` label will also get a benchmark comparison
comment showing any regressions or improvements.

## FAQ

### Where should I put third party propagators/exporters, contrib or standalone crates?

As of now, the specification classify the propagators into three categories:
Fully opened standards, platform-specific standards, proprietary headers. The
conclusion is only the fully opened standards should live in SDK packages/repos.
So here, only fully opened standards should live as independent crate. For more
detail and discussion, see [this
pr](https://github.com/open-telemetry/opentelemetry-specification/pull/1144).
