2019-10-01 18:16:45 +02:00
|
|
|
# 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/1A63zSWX0x2CyCK_LoNhmQC4rqhLpYXJzXbEPDUQ2n6w/edit#heading=h.9tngw7jdwd6b)
|
|
|
|
for a summary description of past meetings. To request edit access,
|
|
|
|
join the meeting or get in touch on
|
2021-02-22 18:38:12 +02:00
|
|
|
[Slack](https://cloud-native.slack.com/archives/C01NPAXACKT).
|
2019-10-01 18:16:45 +02:00
|
|
|
|
|
|
|
## Development
|
|
|
|
|
2020-03-12 18:52:12 +02:00
|
|
|
You can view and edit the source code by cloning this repository:
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
```sh
|
2020-03-12 18:52:12 +02:00
|
|
|
git clone https://github.com/open-telemetry/opentelemetry-go.git
|
|
|
|
```
|
|
|
|
|
2021-04-26 17:42:41 +02:00
|
|
|
Run `make test` to run the tests instead of `go test`.
|
2020-09-10 06:53:27 +02:00
|
|
|
|
2019-10-01 18:16:45 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
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
|
2021-04-26 17:42:41 +02:00
|
|
|
go get -d go.opentelemetry.io/otel
|
2019-10-01 18:16:45 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
(This may print some warning about "build constraints exclude all Go
|
|
|
|
files", just ignore it.)
|
|
|
|
|
2019-11-01 20:40:29 +02:00
|
|
|
This will put the project in `${GOPATH}/src/go.opentelemetry.io/otel`. You
|
2019-10-01 18:16:45 +02:00
|
|
|
can alternatively use `git` directly with:
|
|
|
|
|
|
|
|
```sh
|
2021-04-26 17:42:41 +02:00
|
|
|
git clone https://github.com/open-telemetry/opentelemetry-go
|
2019-10-01 18:16:45 +02:00
|
|
|
```
|
|
|
|
|
2019-11-01 20:40:29 +02:00
|
|
|
(Note that `git clone` is *not* using the `go.opentelemetry.io/otel` name -
|
2019-10-01 18:16:45 +02:00
|
|
|
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
|
2021-04-26 17:42:41 +02:00
|
|
|
git remote add <YOUR_FORK> git@github.com:<YOUR_GITHUB_USERNAME>/opentelemetry-go
|
2019-10-01 18:16:45 +02:00
|
|
|
```
|
|
|
|
|
2020-06-27 02:50:19 +02:00
|
|
|
Check out a new branch, make modifications, run linters and tests, update
|
|
|
|
`CHANGELOG.md`, and push the branch to your fork:
|
2019-10-01 18:16:45 +02:00
|
|
|
|
|
|
|
```sh
|
2021-04-26 17:42:41 +02:00
|
|
|
git checkout -b <YOUR_BRANCH_NAME>
|
2019-10-01 18:16:45 +02:00
|
|
|
# edit files
|
2020-06-27 02:50:19 +02:00
|
|
|
# update changelog
|
2021-04-26 17:42:41 +02:00
|
|
|
make precommit
|
|
|
|
git add -p
|
|
|
|
git commit
|
|
|
|
git push <YOUR_FORK> <YOUR_BRANCH_NAME>
|
2019-10-01 18:16:45 +02:00
|
|
|
```
|
|
|
|
|
2020-06-27 02:50:19 +02:00
|
|
|
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`.
|
2019-10-01 18:16:45 +02:00
|
|
|
|
|
|
|
### 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 to be **ready to merge** when:
|
|
|
|
|
|
|
|
* It has received two approvals from Collaborators/Maintainers (at
|
2020-09-10 20:42:49 +02:00
|
|
|
different companies). This is not enforced through technical means
|
|
|
|
and a PR may be **ready to merge** with a single approval if the change
|
|
|
|
and its approach have been discussed and consensus reached.
|
2021-03-06 00:25:58 +02:00
|
|
|
* Feedback has been addressed.
|
|
|
|
* Any substantive changes to your PR will require that you clear any prior
|
|
|
|
Approval reviews, this includes changes resulting from other feedback. Unless
|
|
|
|
the approver explicitly stated that their approval will persist across
|
|
|
|
changes it should be assumed that the PR needs their review again. Other
|
|
|
|
project members (e.g. approvers, maintainers) can help with this if there are
|
|
|
|
any questions or if you forget to clear reviews.
|
2019-10-01 18:16:45 +02:00
|
|
|
* It has been open for review for at least one working day. This gives
|
|
|
|
people reasonable time to review.
|
2020-09-10 20:42:49 +02:00
|
|
|
* Trivial changes (typo, cosmetic, doc, etc.) do not have to wait for
|
|
|
|
one day and may be merged with a single Maintainer's approval.
|
2020-06-27 02:50:19 +02:00
|
|
|
* `CHANGELOG.md` has been updated to reflect what has been
|
|
|
|
added, changed, removed, or fixed.
|
2019-10-01 18:16:45 +02:00
|
|
|
* Urgent fix can take exception as long as it has been actively
|
|
|
|
communicated.
|
|
|
|
|
2020-09-10 20:42:49 +02:00
|
|
|
Any Maintainer can merge the PR once it is **ready to merge**.
|
2019-10-01 18:16:45 +02:00
|
|
|
|
|
|
|
## Design Choices
|
|
|
|
|
|
|
|
As with other OpenTelemetry clients, opentelemetry-go follows the
|
|
|
|
[opentelemetry-specification](https://github.com/open-telemetry/opentelemetry-specification).
|
|
|
|
|
|
|
|
It's especially valuable to read through the [library
|
2021-02-04 21:13:25 +02:00
|
|
|
guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/library-guidelines.md).
|
2019-10-01 18:16:45 +02:00
|
|
|
|
|
|
|
### 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.
|
|
|
|
|
2021-04-26 17:42:41 +02:00
|
|
|
For a deeper discussion, see
|
|
|
|
[this](https://github.com/open-telemetry/opentelemetry-specification/issues/165).
|
2019-10-01 18:16:45 +02:00
|
|
|
|
|
|
|
## Style Guide
|
|
|
|
|
2020-07-28 19:23:47 +02:00
|
|
|
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
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
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.
|
2020-07-28 19:23:47 +02:00
|
|
|
|
|
|
|
#### `config`
|
|
|
|
|
|
|
|
Configuration should be held in a `struct` named `config`, or prefixed with
|
|
|
|
specific type name this Configuration applies to if there are multiple
|
2021-04-27 20:04:09 +02:00
|
|
|
`config` in the package. This type must contain configuration options.
|
2020-07-28 19:23:47 +02:00
|
|
|
|
|
|
|
```go
|
|
|
|
// config contains configuration options for a thing.
|
|
|
|
type config struct {
|
2021-04-28 17:19:15 +02:00
|
|
|
// options ...
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
In general the `config` type will not need to be used externally to the
|
2020-07-28 19:23:47 +02:00
|
|
|
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 `config` are not shared across package boundaries.
|
|
|
|
Meaning a `config` from one package should not be directly used by another.
|
|
|
|
|
2020-09-11 23:14:25 +02:00
|
|
|
Optionally, it is common to include a `newConfig` function (with the same
|
2020-07-28 19:23:47 +02:00
|
|
|
naming scheme). This function wraps any defaults setting and looping over
|
|
|
|
all options to create a configured `config`.
|
|
|
|
|
|
|
|
```go
|
2020-09-11 23:14:25 +02:00
|
|
|
// newConfig returns an appropriately configured config.
|
|
|
|
func newConfig([]Option) config {
|
2021-04-28 17:19:15 +02:00
|
|
|
// Set default values for config.
|
|
|
|
config := config{/* […] */}
|
|
|
|
for _, option := range options {
|
|
|
|
option.apply(&config)
|
|
|
|
}
|
|
|
|
// Preform any validation here.
|
|
|
|
return config
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
If validation of the `config` options is also preformed 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`,
|
2020-09-11 23:14:25 +02:00
|
|
|
the `newConfig` function should also be unexported.
|
2020-07-28 19:23:47 +02:00
|
|
|
|
|
|
|
#### `Option`
|
|
|
|
|
|
|
|
To set the value of the options a `config` contains, a corresponding
|
|
|
|
`Option` interface type should be used.
|
|
|
|
|
|
|
|
```go
|
|
|
|
type Option interface {
|
2021-04-28 17:19:15 +02:00
|
|
|
apply(*config)
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
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.
|
|
|
|
|
2020-07-28 19:23:47 +02:00
|
|
|
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
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
func (o defaultFalseOption) apply(c *config) {
|
2021-04-28 17:19:15 +02:00
|
|
|
c.Bool = bool(o)
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
// WithOption sets a T to have an option included.
|
2020-07-28 19:23:47 +02:00
|
|
|
func WithOption() Option {
|
2021-04-28 17:19:15 +02:00
|
|
|
return defaultFalseOption(true)
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```go
|
|
|
|
type defaultTrueOption bool
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
func (o defaultTrueOption) apply(c *config) {
|
2021-04-28 17:19:15 +02:00
|
|
|
c.Bool = bool(o)
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
// WithoutOption sets a T to have Bool option excluded.
|
2020-07-28 19:23:47 +02:00
|
|
|
func WithoutOption() Option {
|
2021-04-28 17:19:15 +02:00
|
|
|
return defaultTrueOption(false)
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
2021-04-27 20:04:09 +02:00
|
|
|
```
|
2020-07-28 19:23:47 +02:00
|
|
|
|
|
|
|
##### Declared Type Options
|
|
|
|
|
|
|
|
```go
|
|
|
|
type myTypeOption struct {
|
2021-04-28 17:19:15 +02:00
|
|
|
MyType MyType
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
func (o myTypeOption) apply(c *config) {
|
2021-04-28 17:19:15 +02:00
|
|
|
c.MyType = o.MyType
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
// WithMyType sets T to have include MyType.
|
2020-07-28 19:23:47 +02:00
|
|
|
func WithMyType(t MyType) Option {
|
2021-04-28 17:19:15 +02:00
|
|
|
return myTypeOption{t}
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2021-05-12 03:28:46 +02:00
|
|
|
##### Functional Options
|
|
|
|
|
|
|
|
```go
|
|
|
|
type optionFunc func(*config)
|
|
|
|
|
|
|
|
func (fn optionFunc) apply(c *config) {
|
|
|
|
fn(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithMyType sets t as MyType.
|
|
|
|
func WithMyType(t MyType) Option {
|
|
|
|
return optionFunc(func(c *config) {
|
|
|
|
c.MyType = t
|
|
|
|
})
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2020-07-28 19:23:47 +02:00
|
|
|
#### Instantiation
|
|
|
|
|
2021-04-27 20:04:09 +02:00
|
|
|
Using this configuration pattern to configure instantiation with a `NewT`
|
2020-07-28 19:23:47 +02:00
|
|
|
function.
|
|
|
|
|
|
|
|
```go
|
2021-04-27 20:04:09 +02:00
|
|
|
func NewT(options ...Option) T {…}
|
2020-07-28 19:23:47 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
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 {
|
2021-04-28 17:19:15 +02:00
|
|
|
Weight float64
|
|
|
|
Color string
|
|
|
|
MaxAltitude float64
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// DogOption apply Dog specific options.
|
|
|
|
type DogOption interface {
|
2021-04-28 17:19:15 +02:00
|
|
|
applyDog(*config)
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// BirdOption apply Bird specific options.
|
|
|
|
type BirdOption interface {
|
2021-04-28 17:19:15 +02:00
|
|
|
applyBird(*config)
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Option apply options for all animals.
|
|
|
|
type Option interface {
|
2021-04-28 17:19:15 +02:00
|
|
|
BirdOption
|
|
|
|
DogOption
|
2020-07-28 19:23:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type weightOption float64
|
2021-04-27 20:04:09 +02:00
|
|
|
func (o weightOption) applyDog(c *config) { c.Weight = float64(o) }
|
|
|
|
func (o weightOption) applyBird(c *config) { c.Weight = float64(o) }
|
2020-07-28 19:23:47 +02:00
|
|
|
func WithWeight(w float64) Option { return weightOption(w) }
|
|
|
|
|
|
|
|
type furColorOption string
|
2021-04-27 20:04:09 +02:00
|
|
|
func (o furColorOption) applyDog(c *config) { c.Color = string(o) }
|
2020-07-28 19:23:47 +02:00
|
|
|
func WithFurColor(c string) DogOption { return furColorOption(c) }
|
|
|
|
|
|
|
|
type maxAltitudeOption float64
|
2021-04-27 20:04:09 +02:00
|
|
|
func (o maxAltitudeOption) applyBird(c *config) { c.MaxAltitude = float64(o) }
|
2020-07-28 19:23:47 +02:00
|
|
|
func WithMaxAltitude(a float64) BirdOption { return maxAltitudeOption(a) }
|
|
|
|
|
|
|
|
func NewDog(name string, o ...DogOption) Dog {…}
|
|
|
|
func NewBird(name string, o ...BirdOption) Bird {…}
|
|
|
|
```
|
2019-10-01 18:16:45 +02:00
|
|
|
|
2020-09-16 18:09:45 +02:00
|
|
|
### Interface Type
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2020-01-02 20:59:42 +02:00
|
|
|
## Approvers and Maintainers
|
|
|
|
|
|
|
|
Approvers:
|
|
|
|
|
2020-06-24 00:49:24 +02:00
|
|
|
- [Evan Torrie](https://github.com/evantorrie), Verizon Media
|
2020-08-14 16:53:42 +02:00
|
|
|
- [Josh MacDonald](https://github.com/jmacd), LightStep
|
2020-08-28 23:05:48 +02:00
|
|
|
- [Sam Xie](https://github.com/XSAM)
|
2020-12-18 02:36:49 +02:00
|
|
|
- [David Ashpole](https://github.com/dashpole), Google
|
2021-03-28 17:37:41 +02:00
|
|
|
- [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep
|
2020-01-02 20:59:42 +02:00
|
|
|
|
|
|
|
Maintainers:
|
|
|
|
|
2021-03-09 20:55:46 +02:00
|
|
|
- [Anthony Mirabella](https://github.com/Aneurysm9), AWS
|
|
|
|
- [Tyler Yahn](https://github.com/MrAlias), Splunk
|
2020-01-02 20:59:42 +02:00
|
|
|
|
|
|
|
### Become an Approver or a Maintainer
|
2019-10-01 18:16:45 +02:00
|
|
|
|
|
|
|
See the [community membership document in OpenTelemetry community
|
2021-02-04 21:13:25 +02:00
|
|
|
repo](https://github.com/open-telemetry/community/blob/main/community-membership.md).
|