You can view and edit the source code by cloning this repository:
git clone https://github.com/observiq/stanza.git
Everyone is welcome to contribute code to stanza
via GitHub pull requests (PRs).
To create a new PR, fork the project in GitHub and clone the upstream repo:
$ go get -d github.com/observiq/stanza
This will put the project in ${GOPATH}/src/github.com/observiq/stanza
. You can alternatively use git
directly with:
$ git clone https://github.com/observiq/stanza
This would put the project in the stanza
directory in current working directory.
Enter the newly created directory and add your fork as a new remote:
$ git remote add <YOUR_FORK> git@github.com:<YOUR_GITHUB_USERNAME>/opentelemetry-go
Check out a new branch, make modifications, run linters and tests, and push the branch to your fork:
$ git checkout -b <YOUR_BRANCH_NAME>
# edit files
$ go test -race ./...
$ git add -p
$ git commit
$ git push <YOUR_FORK> <YOUR_BRANCH_NAME>
Open a pull request against the main stanza
repo.
Our CI runs the following checks on each PR. You can run the following local commands to ensure your code is ready for PR:
- Build (
make build
) - Test (
make test
) - Lint (
make lint
)
- If the PR is not ready for review, please put
[WIP]
in the title, tag it aswork-in-progress
, or mark it asdraft
. - If you're stuck, tag a maintainer and ask a question. We're here to help each other.
- Make sure CI passes.
A PR is considered to be ready to merge when:
- It has received approval from at least two maintainers.
- CI passes.
- Major feedback is resolved.
Best practices for developing a builtin operator are documented below, but for changes to the core agent, we are happy to discuss proposals in the issue tracker.
In order to write an operator, follow these three steps:
- Build a unique struct that satisfies the
Operator
interface. This struct will define what your operator does when executed in the pipeline.
type ExampleOperator struct {
FilePath string
}
func (p *ExampleOperator) Process(ctx context.Context, entry *entry.Entry) error {
// Processing logic
}
- Build a unique config struct that satisfies the
Config
interface. This struct will define the parameters used to configure and build your operator struct in step 1.
type ExampleOperatorConfig struct {
filePath string
}
func (c ExampleOperatorConfig) Build(context operator.BuildContext) (operator.Operator, error) {
return &ExampleOperator{
filePath: c.FilePath,
}, nil
}
- Register your config struct in the operator registry using an
init()
hook. This will ensure that the agent knows about your operator at runtime and can build it from a YAML config.
func init() {
operator.RegisterOperator("example_operator", &ExampleOperatorConfig{})
}
We highly recommend that developers take advantage of helpers when building their operators. Helpers are structs that help satisfy common behavior shared across many operators. By embedding these structs, you can skip having to satisfy certain aspects of the operator
and config
interfaces.
For example, almost all operators should embed the BasicOperator helper, as it provides simple functionality for returning an operator id and operator type.
// ExampleOperator is a basic operator, with a basic lifecycle, that consumes
// but doesn't send log entries. Rather than implementing every part of the operator
// interface, we can embed the following helpers to achieve this effect.
type ExampleOperator struct {
helper.BasicOperator
helper.BasicLifecycle
helper.BasicOutput
}