|
| 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(...)`). |
0 commit comments