Skip to content

Commit

Permalink
Merge pull request #25 from wyhaines/kh.the_big_api_to_sdk_shuffle
Browse files Browse the repository at this point in the history
Hold on to your hats.
  • Loading branch information
wyhaines authored Jun 28, 2022
2 parents 6898713 + 4fd4a5d commit db1ce06
Show file tree
Hide file tree
Showing 131 changed files with 1,896 additions and 6,647 deletions.
156 changes: 17 additions & 139 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,12 @@

# OpenTelemetry-API

# TODO: Documentation must be substantially expanded. Click through to the [Full Generated Documentation](#full-generated-documentation) for somewhat more complete documentation.

This library provides the base functionality for implementing services that utilize
OpenTelemetry to send or receive metrics, traces, and logs. This library is intended to be focused specifically on OpenTelemetry itself, with most higher level functionality implemented by other libraries which use this library.

**NOTE:** This shard currently breaks the OpenTelemetry spec because it bundles both API and SDK functionality into a single repository/library. This [issue](https://github.com/wyhaines/opentelemetry-api.cr/issues/5) will be addressed very soon, and the SDK functionality will all be moved over to [https://github.com/wyhaines/opentelemetry-sdk.cr](https://github.com/wyhaines/opentelemetry-sdk.cr).

As a general rule, naming conventions have been based on the standard glossary of OpenTelementry terms, as found at [https://opentelemetry.io/docs/concepts/glossary/](https://opentelemetry.io/docs/concepts/glossary/)

The general architecture of the implementation is guided by this document:

[https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md)

The TL;DR is that a `TracerProvider` is used to create a `Tracer`. A `Span` is created inside of the context of a `Tracer`, and one `Span` may nest inside of another.
This is an implementation of the OpenTelemetry API. The API layer provides a set of interface definitions, and NO-OP implementations of those interfaces. It is not useful on its own to instrument your code with OpenTelemetry, but rather is intended to be used by the [SDK], which provides the functionality behind the API interfaces defined in this repo.

## Full Generated Documentation

[https://wyhaines.github.io/opentelemetry-api.cr/](https://wyhaines.github.io/opentelemetry-api.cr/)

A lot of documentation needs to be added. PRs would be welcome!

## Discord

A Discord community for help and discussion with Crystal OpenTelemetry can be found at:
Expand All @@ -33,6 +18,10 @@ https://discord.gg/WKe9WWJ3HE

## Installation

You will not normally directly use this shard. If you want to instrument your code with OpenTelemetry, see the [Instrumentation shard](https://github.com/wyhaines/opentelemetry-instrumentation.cr/) or the [SDK].

If you do have reason to use this shard directly, however:

1. Add the dependency to your `shard.yml`:

```yaml
Expand All @@ -45,143 +34,29 @@ https://discord.gg/WKe9WWJ3HE

## Usage

```crystal
require "opentelemetry-api"
```

## Global Tracer Provider

The most common pattern for usage is to have a single global `TracerProvider` that is configured early in the program's execution. One may create an explicit configuration block, which will configure a globally held `TracerProvider`:

```crystal
OpenTelemetry.configure do |config|
config.service_name = "my_app_or_library"
config.service_version = "1.1.1"
config.exporter = OpenTelemetry::Exporter.new(variant: :stdout)
end
```

One may also provision a `TracerProvider` object directly:

```crystal
tracer_provider = OpenTelemetry.tracer_provider("my_app_or_library", "1.1.1")
tracer_provider = OpenTelemetry.tracer_provider do |tracer|
tracer.service_name = "my_app_or_library"
tracer.service_version = "1.1.1"
end
```

This allows multiple providers with different configuration to be created:

```crystal
provider_a = OpenTelemetry::TracerProvider.new("my_app_or_library", "1.1.1")
provider_a.exporter = OpenTelemetry::Exporter.new(variant: :stdout)
```

```crystal
provider_b = OpenTelementry::TracerProvider.new do |config|
config.service_name = "my_app_or_library"
config.service_version = "1.1.1"
config.exporter = OpenTelemetry::Exporter.new(variant: :stdout)
end
```

All `TracerProvider` configuration done in this way will respect OpenTelemetry SDK conventions for environment variable based configuration. Configuration delivered via environment variables supercedes configuration delivered in code. For example:

*environment variables*
```bash
OTEL_SERVICE_NAME="FIB ON COMMAND"
OTEL_SERVICE_VERSION="1.1.1"
OTEL_TRACES_EXPORTER="stdout"
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG="0.10"
```

*configuration code*
```crystal
OpenTelemetry.configure do |config|
config.service_name = "Fibonacci Server"
config.service_version = Fibonacci::VERSION
config.exporter = OpenTelemetry::Exporter.new(variant: :http) do |exporter|
exporter = exporter.as(OpenTelemetry::Exporter::Http)
exporter.endpoint = "https://otlp.nr-data.net:4318/v1/traces"
headers = HTTP::Headers.new
headers["api-key"] = ENV["NEW_RELIC_LICENSE_KEY"]?.to_s
exporter.headers = headers
end
end
```

In the above code, the code specifies a default set of configuration, which includes setting up an exporter to send traces to New Relic. The environment variable based configuration will override that configuration, however, and will instead setup a Stdout exporter with a sampler that only sends 10% of the traces to the exporter.

If one knows that one will be depending on environment variable based configuration, the initial configuration of the OpenTelemetry library can be simplified down to:
To gain access to all of the API (i.e. NO-OP) implementations of the OTel API interfaces:

```crystal
OpenTelemetry.configure
```

The SDK will support the full range of environment variable based configuration ([https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md)), but currently only a minimal subset is supported:

- OTEL_SERVICE_NAME
- OTEL_SERVICE_VERSION
- OTEL_SCHEMA_URL
- OTEL_TRACES_SAMPLER
- OTEL_TRACES_SAMPLER_ARG
- OTEL_TRACES_EXPORTER

## Getting a Tracer From a Provider Object

Most typically, when using a default `TracerProvider`, the SDK will be leveraged to produce a Tracer like so:

```crystal
OpenTelemetry.tracer.in_span("I am a span") do |span|
span.set_attribute("key1", "value1")
span.set_attribute("key2", "value2")
span.set_attribute("key3", "value3")
do_some_work
end
```

If one wishes to override the configuration held by a `TracerProvider` when creating a `Tracer`, new configuration can be provided in the `#tracer` method call:

```crystal
tracer = provider_a.tracer("microservice foo", "1.2.3") # Override the configuration
```

```crystal
tracer = provider_a.tracer do |tracer|
tracer.service_name = "microservice foo"
tracer.service_version = "1.2.3"
end
require "opentelemetry-api"
```

This new configuration only applies to the specific `Tracer` instance created. It does not alter the `TracerProvider` configuration.
This will define a set of classes and structs which implement the OpenTelemetry API interfaces with methods that do nothing.

## Creating Spans Using a Tracer
-----
If you only want access to the API interfaces (which is what the [SDK] uses):

```crystal
tracer.in_span("request") do |span|
span.set_attribute("verb", "GET")
span.set_attribute("url", "http://example.com/foo")
span.add_event("dispatching to handler")
tracer.in_span("handler") do |child_span|
child_span.add_event("handling request")
tracer.in_span("db") do |child_span|
child_span.add_event("querying database")
end
end
end
require "opentelemetry-api/src/interfaces"
```

## Development

TODO: Write development instructions here
If you want to help with development, [fork](https://github.com/wyhaines/opentelemetry-api.cr/fork) this repo. Do your work in a branch inside your fork, and when it is ready (and has specs), submit a PR. See [Contributing] below.

If you have a question or find an issue, you can [start a discussion](https://github.com/wyhaines/opentelemetry-api.cr/discussions/new) or [create an issue](https://github.com/wyhaines/opentelemetry-api.cr/issues/new/choose).

## Contributing

1. Fork it (<https://github.com/your-github-user/otel/fork>)
1. Fork it (https://github.com/wyhaines/opentelemetry-api.cr/fork)
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
Expand All @@ -193,3 +68,6 @@ TODO: Write development instructions here

![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/wyhaines/opentelemetry-api.cr?style=for-the-badge)
![GitHub issues](https://img.shields.io/github/issues/wyhaines/opentelemetry-api.cr?style=for-the-badge)

[Contributing]: #contributing
[SDK]: https://github.com/wyhaines/opentelemetry-sdk.cr
30 changes: 1 addition & 29 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,3 @@
# Roadmap

This document represents a general set of goals for the project. It will change over time, and should be taken as a document that presents a general vision and plan for what is to come, and not as a document with specific tasks or milestones expressed. All specific goals and tasks will be found [as issues](https://github.com/wyhaines/opentelemetry-api.cr/issues).

- Separate SDK from the API.

Currently the SDK and the API are combined into this single repository, but that is the wrong thing to be doing. The SDK capabilities must move [to their own repository](https://github.com/wyhaines/opentelemetry-sdk.cr).

- Improved Spec Compliance

The current implementation is a work in progress, with areas where the spec is implemented incompletely or incorrectly. These omissions and transgressions must be addressed.

- Improve Documentation

It is not expected that people will use the API directly, but there should be more robust documentation available for those who have a need to interact with it directly.

- Implement Baggage

Support for TraceContext exists. Compliment this with support for the Baggage standard for data interchange.

- Add Log support

The protobuf standard for Log is now stable, so Log support should be finalized and made usable, as it is already partially implemented.

- Add Metrics

Metrics are stable, and are very important. They are, however, also complicated, but that can cannot be kicked down the road for too much longer. Metric support needs to be implemented.

- Make OTLP/gRPC work

This largely depends on external work to ensure that there is a solid HTTP2 implementation available. Once that exists, however, OTLP/gRPC should be about done.
See the master roadmap in the [SDK](https://github.com/wyhaines/opentelemetry-sdk.cr/blob/main/ROADMAP.md) repository.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.4
0.5.0
8 changes: 1 addition & 7 deletions shard.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: opentelemetry-api
version: 0.3.4
version: 0.5.0

authors:
- Kirk Haines <wyhaines@gmail.com>
Expand All @@ -9,8 +9,6 @@ crystal: ">1.1.0"
license: "Apache 2.0"

dependencies:
db:
github: crystal-lang/crystal-db
splay_tree_map:
github: wyhaines/splay_tree_map.cr
nbchannel:
Expand All @@ -22,10 +20,6 @@ dependencies:
time-ext:
github: wyhaines/time-ext.cr
branch: main
protobuf:
github: jeromegn/protobuf.cr
retriable:
github: Sija/retriable.cr
debug:
github: Sija/debug.cr

Expand Down
96 changes: 0 additions & 96 deletions spec/context_spec.cr

This file was deleted.

Loading

0 comments on commit db1ce06

Please sign in to comment.