Skip to content
This repository was archived by the owner on Oct 31, 2024. It is now read-only.

Commit 4c98e01

Browse files
author
Amir Blum
authored
docs: add conventions and developer guide (#92)
1 parent d371777 commit 4c98e01

File tree

3 files changed

+156
-1
lines changed

3 files changed

+156
-1
lines changed

README.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@
1212
</a>
1313
</p>
1414

15+
<p>
16+
<strong>
17+
<a href="doc/conventions.md">Conventions<a/>
18+
&nbsp;&nbsp;&bull;&nbsp;&nbsp;
19+
<a href="doc/development-guide.md">Development Guide<a/>
20+
</strong>
21+
</p>
22+
23+
---
24+
1525
js extensions for the [open-telemetry](https://opentelemetry.io/) project, from [Aspecto](https://www.aspecto.io/) with :heart:
1626

1727
**Compatible with [otel v0.18.0](https://github.com/open-telemetry/opentelemetry-js/releases/tag/v0.18.0)**
@@ -35,4 +45,4 @@ For documentation using with the old [plugin](https://github.com/open-telemetry/
3545
- Versions **0.3.x** of the instrumentations are compatible with otel version v0.18.0
3646
- Versions **0.2.x** of the instrumentations are compatible with otel version v0.17.0
3747
- Versions **0.1.x** of the instrumentations are compatible with otel version v0.16.0
38-
- Versions **0.0.x** of the instrumentations are compatible with otel version v0.15.0
48+
- Versions **0.0.x** of the instrumentations are compatible with otel version v0.15.0

doc/conventions.md

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Instrumentation Libraries Conventions
2+
This document is an extension to the [open telemetry Trace Semantic Conventions](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/trace/semantic_conventions) document. It records additional conventions which we found useful for the instrumentations in this repo.
3+
4+
## Instrumentation Configuration
5+
6+
### moduleVersionAttributeName
7+
```
8+
Type: string
9+
Required in each plugin: true
10+
Default: undefined
11+
```
12+
13+
Instrumentation SHOULD support automatic collection of instrumented library version into a span attribute. The span attribute name is the value of the `moduleVersionAttributeName` option, and the span attribute value is the version of the instrumented library.
14+
15+
If instrumentation library is patching multiple npm packages, each with a different version, then the library should pick the version of the most suited package and attach it to this attribute.
16+
17+
### suppressInternalInstrumentation
18+
```
19+
Type: boolean
20+
Required in each plugin: false
21+
Default: false
22+
```
23+
24+
Some instrumented libraries are using internally other packages which are instrumented as well. For example:
25+
- aws-sdk is using http for the internal RPC requests to various services.
26+
- elasticsearch client is communicating with the db via http.
27+
- mongoose (and other ORMs), are using database drivers to access the database.
28+
29+
For some users, viewing the internal details of clients underlying protocol is important. Others only takes interest in the client instrumentation, and instrumenting the communication protocol just creates extra visual and performance load.
30+
31+
If this attribute is set to `true`, then the instrumentation library should suppress the internal spans which are generated by calls to library functions.
32+
33+
This is an optional config option, which should be used only in libraries which use an instrumented underlying protocol. Notice that suppressInstrumentation is not recommended when context needs to be propagated. So if propagation of context is used in some use case (supported by the receiving side), then this option should not be used.
34+
35+
### ignoreOrphanedSpans
36+
```
37+
Type: boolean
38+
Required in each plugin: false
39+
Default: false
40+
```
41+
42+
The `ignoreOrphanedSpans` is not well standardized across the opentelemetry js ecosystem. It is sometimes called by the names `requireParent` and `requireParentSpan` in contrib and core repo.
43+
44+
In general, we can categorized traces into two categories:
45+
1. Traces that starts due to some external input to the application, usually a user-triggered event (incoming http request, message received on queue, etc).
46+
2. Traces that are triggered by some internal behavior:
47+
- Timers
48+
- Initialization code
49+
- Operation that have a trace context, but it was lost while running the code. This can happen when using [thenables](https://github.com/nodejs/node/issues/22360), event emitters, and other cases which break context management.
50+
51+
Some users want to see all the operations in the application, not hiding anything. Those users will set `ignoreOrphanedSpans` to `false` (or leave it with the default value which is `false`).
52+
53+
Other users may want to see only "external-triggered" traces, and reduce the noisy and performance impact by not instrumenting the internal operations. Those users will want to set the `ignoreOrphanedSpans` option to `true`.
54+
55+
Ignoring spans can be done in many flavors, and the relevant considerations should be taken into account for each case, and documented for each library.
56+
- skip instrumentation - just call the original function and don't executed any instrumentation related code.
57+
- suppressInstrumentation - this method will also ignore downstream spans, which might not be desired.
58+
- NoRecordingSpan - create no recording span instead of a regular recording span. This method can influence downstream spans which are using parent based sampling.
59+
Unless there is a good reason not to, instrumentation libraries should ignore orphaned spans by skipping instrumentation (calling `original.apply(this, arguments)`).
60+
61+
### Hooks
62+
```
63+
Type: function
64+
Required in each plugin: true
65+
Default: undefined
66+
```
67+
68+
Each instrumentation library should expose hooks which can be configured to add custom logic and attributes to span on various lifecycle events.
69+
This will usually be `requestHook` and `responseHook`, but can be anything depending on the specific case.
70+
71+
Each hook is a function that receives relevant parameters. Some common parameters are:
72+
- The current span which is relevant to the hook
73+
- Original call parameters
74+
- Response that will be returned to user
75+
- Version of the instrumented library.
76+
77+
The hooks can be used for any purpose, but some common use cases are:
78+
- Capturing additional operation data into custom span attributes (http headers, payloads, etc).
79+
- Registering to event emitters or patching objects for custom instrumentation extensions.
80+
- Setting global attributes for the component which are not part of the semantic conventions.
81+
82+
Exceptions should not be thrown from hook functions, but instrumentation should protect itself for this case by catching hooks exceptions and write to diag logger.
83+
84+
## Logging
85+
Instrumentations should write diagnostic logs to `diag` api in `@opentelemetry/api`.
86+
Events that should be written are:
87+
- (info) Patching and unpatching of library functions
88+
- (error) Exception thrown from custom hook
89+
90+
The log message should have the prefix `${component} instrumentation: ${message}`, for example: `mongoose instrumentation: patching mongoose Aggregate exec prototype`.
91+
92+
## Instrumentation Class
93+
All the private functions in instrumentation class should have camelCase, with no leading underscore:
94+
(`private patchConnect(...)`).

doc/development-guide.md

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Developer Guide
2+
This guide audience is developers writing a new instrumentation, maintaining existing instrumentation, or trying to understand the architecture and design decisions of instrumentation in this repo.
3+
4+
It is meant to document various aspects of developing instrumentation library, based on the experiences we gained with the packages in this repo.
5+
6+
## Unpatching
7+
TODO
8+
9+
## Configuration
10+
Each instrumentation library should have configuration interface under `types.ts`. All the configuration parameters must be optional, and should have default value which is documented in the README.md of the package.
11+
12+
Supplied configuration should be merged with default configuration object so that defaults are obvious:
13+
14+
```js
15+
export const DEFAULT_CONFIG: FooInstrumentationConfig = {
16+
barOptions: 'some default value for bar',
17+
};
18+
19+
export class FooInstrumentation extends InstrumentationBase<typeof foo> {
20+
protected _config: FooInstrumentationConfig;
21+
22+
constructor(config: FooInstrumentationConfig = {}) {
23+
super('opentelemetry-instrumentation-amqplib', VERSION, Object.assign({}, DEFAULT_CONFIG, config));
24+
}
25+
}
26+
```
27+
28+
## Holding References to Objects
29+
TODO
30+
31+
## Close Span on Exception
32+
Each span that is started should be ended. This is usually done after receiving the response for the operation.
33+
A common error is not ending the span in case an exception was thrown (skips the code that calls `span.end()`).
34+
35+
You can use the `safeExecuteInTheMiddle` util from `@opentelemetry/instrumentation` for this task.
36+
37+
## Using Mocks vs Docker in Tests
38+
TODO
39+
40+
## Utils vs Instrumentation Class
41+
TODO
42+
43+
## Test All Versions
44+
Each instrumentation must set package.json script called `test:ci` which runs [test-all-versions](https://www.npmjs.com/package/test-all-versions) on all the versions which are supported by the instrumentation.
45+
46+
# Checklist before submitting a PR
47+
- [ ] Supported version range is specified
48+
- [ ] [test-all-versions](https://www.npmjs.com/package/test-all-versions) is configured to run on `test:ci` with all supported versions.
49+
- [ ] PR to add new instrumentation to [open telemetry registry](https://github.com/open-telemetry/opentelemetry.io)
50+
- [ ] Verify that instrumented library is a dev dependency
51+
- [ ] Verify you only import from instrumented library with type: `import type x from 'y'`. A valid otel setup can install the plugin but not the instrumented library, in which case importing directly will fail and crash the application.

0 commit comments

Comments
 (0)