mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 06:26:26 +00:00
feat(telemetry): add OpenTelemetry tracing MVC (#15731)
This commit is contained in:
parent
b5a515b533
commit
b53c581e5c
19 changed files with 1055 additions and 36 deletions
BIN
docs/usage/assets/images/opentelemetry_choose_trace.png
Normal file
BIN
docs/usage/assets/images/opentelemetry_choose_trace.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
BIN
docs/usage/assets/images/opentelemetry_pick_service.png
Normal file
BIN
docs/usage/assets/images/opentelemetry_pick_service.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
docs/usage/assets/images/opentelemetry_trace_viewer.png
Normal file
BIN
docs/usage/assets/images/opentelemetry_trace_viewer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 262 KiB |
233
docs/usage/examples/opentelemetry.md
Normal file
233
docs/usage/examples/opentelemetry.md
Normal file
|
@ -0,0 +1,233 @@
|
|||
# OpenTelemetry
|
||||
|
||||
Requirements:
|
||||
|
||||
- docker-compose
|
||||
|
||||
## Prepare setup
|
||||
|
||||
Create a `docker-compose.yaml` and `otel-collector-config.yml` file as seen below in a folder.
|
||||
|
||||
`docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
services:
|
||||
# Jaeger
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:1
|
||||
ports:
|
||||
- '16686:16686'
|
||||
- '14250'
|
||||
|
||||
otel-collector:
|
||||
image: otel/opentelemetry-collector-contrib:0.52.0
|
||||
command: ['--config=/etc/otel-collector-config.yml']
|
||||
volumes:
|
||||
- ./otel-collector-config.yml:/etc/otel-collector-config.yml
|
||||
ports:
|
||||
- '1888:1888' # pprof extension
|
||||
- '13133:13133' # health_check extension
|
||||
- '55679:55679' # zpages extension
|
||||
- '4318:4318' # OTLP HTTP
|
||||
- '4317:4317' # OTLP GRPC
|
||||
- '9123:9123' # Prometheus exporter
|
||||
depends_on:
|
||||
- jaeger
|
||||
```
|
||||
|
||||
`otel-collector-config.yml`:
|
||||
|
||||
```yaml
|
||||
receivers:
|
||||
otlp:
|
||||
protocols:
|
||||
grpc:
|
||||
http:
|
||||
|
||||
exporters:
|
||||
jaeger:
|
||||
endpoint: jaeger:14250
|
||||
tls:
|
||||
insecure: true
|
||||
logging:
|
||||
prometheus:
|
||||
endpoint: '0.0.0.0:9123'
|
||||
|
||||
processors:
|
||||
batch:
|
||||
spanmetrics:
|
||||
metrics_exporter: prometheus
|
||||
latency_histogram_buckets: [10ms, 100ms, 250ms, 1s, 30s, 1m, 5m]
|
||||
dimensions:
|
||||
- name: http.method
|
||||
- name: http.status_code
|
||||
- name: http.host
|
||||
dimensions_cache_size: 1000
|
||||
aggregation_temporality: 'AGGREGATION_TEMPORALITY_CUMULATIVE'
|
||||
|
||||
extensions:
|
||||
health_check:
|
||||
pprof:
|
||||
zpages:
|
||||
|
||||
service:
|
||||
extensions: [pprof, zpages, health_check]
|
||||
pipelines:
|
||||
traces:
|
||||
receivers: [otlp]
|
||||
exporters: [jaeger, logging]
|
||||
processors: [spanmetrics, batch]
|
||||
|
||||
metrics:
|
||||
receivers: [otlp]
|
||||
exporters: [prometheus]
|
||||
```
|
||||
|
||||
Start setup using this command inside the folder containing the files created in the earlier steps:
|
||||
|
||||
```
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
This command will start an [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector-contrib) and an instance of [Jaeger](https://www.jaegertracing.io/).
|
||||
|
||||
Jaeger will be now reachable under [http://localhost:16686](http://localhost:16686).
|
||||
|
||||
## Run Renovate with OpenTelemetry
|
||||
|
||||
To start Renovate with OpenTelemetry enabled run following command, after pointing to your `config.js` config file:
|
||||
|
||||
```
|
||||
docker run \
|
||||
--rm \
|
||||
-e OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
|
||||
-v "/path/to/your/config.js:/usr/src/app/config.js" \
|
||||
renovate/renovate:latest
|
||||
```
|
||||
|
||||
You should now see `trace_id` and `span_id` fields in the logs.
|
||||
|
||||
```
|
||||
INFO: Repository finished (repository=org/example)
|
||||
"durationMs": 5574,
|
||||
"trace_id": "f9a4c33852333fc2a0fbdc163100c987",
|
||||
"span_id": "4ac1323eeaee
|
||||
```
|
||||
|
||||
### Traces
|
||||
|
||||
Open now Jaeger under [http://localhost:16686](http://localhost:16686).
|
||||
|
||||
You should now be able to pick `renovate` under in the field `service` field.
|
||||
|
||||
![service picker](../assets/images/opentelemetry_pick_service.png)
|
||||
|
||||
Press `Find Traces` to search for all Renovate traces and then click on one of the found traces to open the trace view.
|
||||
|
||||
![pick trace](../assets/images/opentelemetry_choose_trace.png)
|
||||
|
||||
You should be able to see now the full trace view which shows each HTTP request and internal spans.
|
||||
|
||||
![trace view](../assets/images/opentelemetry_trace_viewer.png)
|
||||
|
||||
### Metrics
|
||||
|
||||
Additional to the received traces some metrics are calculated.
|
||||
This is achieved using the [spanmetricsprocessor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/spanmetricsprocessor).
|
||||
The previous implemented setup will produce following metrics, which are exposed under [http://localhost:9123/metrics](http://localhost:9123/metrics):
|
||||
|
||||
```
|
||||
# HELP calls_total
|
||||
# TYPE calls_total counter
|
||||
|
||||
### Example of internal spans
|
||||
calls_total{operation="renovate repository",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET"} 3
|
||||
calls_total{operation="run",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET"} 1
|
||||
### Example of http calls from Renovate to external services
|
||||
calls_total{http_host="api.github.com:443",http_method="POST",http_status_code="200",operation="HTTPS POST",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET"} 9
|
||||
|
||||
...
|
||||
|
||||
# HELP latency
|
||||
# TYPE latency histogram
|
||||
### Example of internal spans
|
||||
latency_bucket{operation="renovate repository",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET",le="0.1"} 0
|
||||
...
|
||||
latency_bucket{operation="renovate repository",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET",le="9.223372036854775e+12"} 3
|
||||
latency_bucket{operation="renovate repository",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET",le="+Inf"} 3
|
||||
latency_sum{operation="renovate repository",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET"} 30947.4689
|
||||
latency_count{operation="renovate repository",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET"} 3
|
||||
|
||||
...
|
||||
|
||||
### Example of http calls from Renovate to external services
|
||||
latency_bucket{http_host="api.github.com:443",http_method="POST",http_status_code="200",operation="HTTPS POST",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET",le="0.1"} 0
|
||||
...
|
||||
latency_bucket{http_host="api.github.com:443",http_method="POST",http_status_code="200",operation="HTTPS POST",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET",le="250"} 3
|
||||
latency_bucket{http_host="api.github.com:443",http_method="POST",http_status_code="200",operation="HTTPS POST",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET",le="9.223372036854775e+12"} 9
|
||||
latency_bucket{http_host="api.github.com:443",http_method="POST",http_status_code="200",operation="HTTPS POST",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET",le="+Inf"} 9
|
||||
latency_sum{http_host="api.github.com:443",http_method="POST",http_status_code="200",operation="HTTPS POST",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET"} 2306.1385999999998
|
||||
latency_count{http_host="api.github.com:443",http_method="POST",http_status_code="200",operation="HTTPS POST",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET"} 9
|
||||
```
|
||||
|
||||
The [spanmetricsprocessor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/spanmetricsprocessor) creates two sets of metrics.
|
||||
|
||||
#### Calls metric
|
||||
|
||||
At first there are the `calls_total` metrics which display how often specific trace spans have been observed.
|
||||
|
||||
For example:
|
||||
`calls_total{operation="renovate repository",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET"} 3` signals that 3 repositories have been renovated.
|
||||
`calls_total{operation="run",service_name="renovate",span_kind="SPAN_KIND_INTERNAL",status_code="STATUS_CODE_UNSET"} 1` represents how often Renovate has been run.
|
||||
|
||||
If we combine this using the PrometheusQueryLanguage ( PromQL ), we can calculate the average count of repositories each Renovate run handles.
|
||||
|
||||
```
|
||||
calls_total{operation="renovate repository",service_name="renovate"} / calls_total{operation="run",service_name="renovate"}
|
||||
```
|
||||
|
||||
This metrics is also for spans generated by http calls:
|
||||
|
||||
```yaml
|
||||
calls_total{http_host="registry.terraform.io:443",http_method="GET",http_status_code="200",operation="HTTPS GET",service_name="renovate",span_kind="SPAN_KIND_CLIENT",status_code="STATUS_CODE_UNSET"} 5
|
||||
```
|
||||
|
||||
#### Latency buckets
|
||||
|
||||
The second class of metrics exposed are the latency focused latency buckets which allow to create [heatmaps](https://grafana.com/docs/grafana/latest/basics/intro-histograms/#heatmaps).
|
||||
A request is added to a backed if the latency is bigger than the bucket value (`le`). `request_duration => le`
|
||||
|
||||
As an example if we receive a request which need `1.533s` to complete get following metrics:
|
||||
|
||||
```
|
||||
latency_bucket{http_host="api.github.com:443",le="0.1"} 0
|
||||
latency_bucket{http_host="api.github.com:443",le="1"} 0
|
||||
latency_bucket{http_host="api.github.com:443",le="2"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="6"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="10"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="100"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="250"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="9.223372036854775e+12"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="+Inf"} 1
|
||||
latency_sum{http_host="api.github.com:443"} 1.533
|
||||
latency_count{http_host="api.github.com:443"} 1
|
||||
```
|
||||
|
||||
Now we have another request which this time takes 10s to complete:
|
||||
|
||||
```
|
||||
latency_bucket{http_host="api.github.com:443",le="0.1"} 0
|
||||
latency_bucket{http_host="api.github.com:443",le="1"} 0
|
||||
latency_bucket{http_host="api.github.com:443",le="2"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="6"} 1
|
||||
latency_bucket{http_host="api.github.com:443",le="10"} 2
|
||||
latency_bucket{http_host="api.github.com:443",le="100"} 2
|
||||
latency_bucket{http_host="api.github.com:443",le="250"} 2
|
||||
latency_bucket{http_host="api.github.com:443",le="9.223372036854775e+12"} 2
|
||||
latency_bucket{http_host="api.github.com:443",le="+Inf"} 2
|
||||
latency_sum{http_host="api.github.com:443"} 11.533
|
||||
latency_count{http_host="api.github.com:443"} 2
|
||||
```
|
||||
|
||||
More about the functionality can be found on the Prometheus page for [metric types](https://prometheus.io/docs/concepts/metric_types/#histogram).
|
30
docs/usage/opentelemetry.md
Normal file
30
docs/usage/opentelemetry.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
title: OpenTelemetry
|
||||
description: How to use OpenTelemetry with Renovate
|
||||
---
|
||||
|
||||
# OpenTelemetry and Renovate
|
||||
|
||||
**THIS FEATURE IS EXPERIMENTAL** and is subject to change in minor versions.
|
||||
|
||||
Renovate supports OpenTelemetry which is an emerging monitoring standard.
|
||||
|
||||
OpenTelemetry supports three types of observability data:
|
||||
|
||||
- traces
|
||||
- metrics
|
||||
- logs
|
||||
|
||||
Renovate can only send traces and only via the OpenTelemetryProtocol (OTLP), other observability data or transfer protocols are not supported.
|
||||
|
||||
## Usage
|
||||
|
||||
To activate the instrumentation, the environment variable `OTEL_EXPORTER_OTLP_ENDPOINT` has to be set.
|
||||
This sets the endpoint where to send the telemetry data.
|
||||
If this endpoint is set, all other environment variables defined by the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md) are supported.
|
||||
|
||||
For debugging purposes the telemetry can also be printed to the console if the environment variable `RENOVATE_TRACING_CONSOLE_EXPORTER` is set.
|
||||
|
||||
## Examples
|
||||
|
||||
An usage example with a local OpenTelemetry setup can be found in the [OpenTelemetry examples](examples/opentelemetry.md)
|
|
@ -62,3 +62,8 @@ Source: [AWS s3 documentation - Interface BucketEndpointInputConfig](https://doc
|
|||
## `RENOVATE_X_EXEC_GPID_HANDLE`
|
||||
|
||||
If set, Renovate will terminate the whole process group of a terminated child process spawned by Renovate.
|
||||
|
||||
## `OTEL_EXPORTER_OTLP_ENDPOINT`
|
||||
|
||||
If set, Renovate will export OpenTelemetry data to the supplied endpoint.
|
||||
For more information see [the OpenTelemetry docs](opentelemetry.md).
|
||||
|
|
5
lib/instrumentation/__mocks__/index.ts
Normal file
5
lib/instrumentation/__mocks__/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { NoopTracer } from '@opentelemetry/api/build/src/trace/NoopTracer';
|
||||
import { NoopTracerProvider } from '@opentelemetry/api/build/src/trace/NoopTracerProvider';
|
||||
|
||||
export const getTracerProvider = jest.fn(args => new NoopTracerProvider());
|
||||
export const getTracer = jest.fn(args => new NoopTracer());
|
124
lib/instrumentation/__snapshots__/index.spec.ts.snap
Normal file
124
lib/instrumentation/__snapshots__/index.spec.ts.snap
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`instrumentation/index activate console logger 1`] = `
|
||||
MultiSpanProcessor {
|
||||
"_spanProcessors": [
|
||||
SimpleSpanProcessor {
|
||||
"_exporter": ConsoleSpanExporter {},
|
||||
"_shutdownOnce": BindOnceFuture {
|
||||
"_callback": [Function],
|
||||
"_deferred": Deferred {
|
||||
"_promise": Promise {},
|
||||
"_reject": [Function],
|
||||
"_resolve": [Function],
|
||||
},
|
||||
"_isCalled": false,
|
||||
"_that": [Circular],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`instrumentation/index activate console logger and remote logger 1`] = `
|
||||
MultiSpanProcessor {
|
||||
"_spanProcessors": [
|
||||
SimpleSpanProcessor {
|
||||
"_exporter": ConsoleSpanExporter {},
|
||||
"_shutdownOnce": BindOnceFuture {
|
||||
"_callback": [Function],
|
||||
"_deferred": Deferred {
|
||||
"_promise": Promise {},
|
||||
"_reject": [Function],
|
||||
"_resolve": [Function],
|
||||
},
|
||||
"_isCalled": false,
|
||||
"_that": [Circular],
|
||||
},
|
||||
},
|
||||
BatchSpanProcessor {
|
||||
"_exportTimeoutMillis": 30000,
|
||||
"_exporter": OTLPTraceExporter {
|
||||
"DEFAULT_HEADERS": {},
|
||||
"_concurrencyLimit": Infinity,
|
||||
"_sendingPromises": [],
|
||||
"_shutdownOnce": BindOnceFuture {
|
||||
"_callback": [Function],
|
||||
"_deferred": Deferred {
|
||||
"_promise": Promise {},
|
||||
"_reject": [Function],
|
||||
"_resolve": [Function],
|
||||
},
|
||||
"_isCalled": false,
|
||||
"_that": [Circular],
|
||||
},
|
||||
"agent": undefined,
|
||||
"compression": "none",
|
||||
"headers": {},
|
||||
"shutdown": [Function],
|
||||
"timeoutMillis": 10000,
|
||||
"url": "https://collector.example.com/v1/traces",
|
||||
},
|
||||
"_finishedSpans": [],
|
||||
"_maxExportBatchSize": 512,
|
||||
"_maxQueueSize": 2048,
|
||||
"_scheduledDelayMillis": 5000,
|
||||
"_shutdownOnce": BindOnceFuture {
|
||||
"_callback": [Function],
|
||||
"_deferred": Deferred {
|
||||
"_promise": Promise {},
|
||||
"_reject": [Function],
|
||||
"_resolve": [Function],
|
||||
},
|
||||
"_isCalled": false,
|
||||
"_that": [Circular],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`instrumentation/index activate remote logger 1`] = `
|
||||
MultiSpanProcessor {
|
||||
"_spanProcessors": [
|
||||
BatchSpanProcessor {
|
||||
"_exportTimeoutMillis": 30000,
|
||||
"_exporter": OTLPTraceExporter {
|
||||
"DEFAULT_HEADERS": {},
|
||||
"_concurrencyLimit": Infinity,
|
||||
"_sendingPromises": [],
|
||||
"_shutdownOnce": BindOnceFuture {
|
||||
"_callback": [Function],
|
||||
"_deferred": Deferred {
|
||||
"_promise": Promise {},
|
||||
"_reject": [Function],
|
||||
"_resolve": [Function],
|
||||
},
|
||||
"_isCalled": false,
|
||||
"_that": [Circular],
|
||||
},
|
||||
"agent": undefined,
|
||||
"compression": "none",
|
||||
"headers": {},
|
||||
"shutdown": [Function],
|
||||
"timeoutMillis": 10000,
|
||||
"url": "https://collector.example.com/v1/traces",
|
||||
},
|
||||
"_finishedSpans": [],
|
||||
"_maxExportBatchSize": 512,
|
||||
"_maxQueueSize": 2048,
|
||||
"_scheduledDelayMillis": 5000,
|
||||
"_shutdownOnce": BindOnceFuture {
|
||||
"_callback": [Function],
|
||||
"_deferred": Deferred {
|
||||
"_promise": Promise {},
|
||||
"_reject": [Function],
|
||||
"_resolve": [Function],
|
||||
},
|
||||
"_isCalled": false,
|
||||
"_that": [Circular],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
49
lib/instrumentation/decorator.spec.ts
Normal file
49
lib/instrumentation/decorator.spec.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { afterAll } from '@jest/globals';
|
||||
import { instrument } from './decorator';
|
||||
import { disableInstrumentations } from '.';
|
||||
|
||||
afterAll(disableInstrumentations);
|
||||
|
||||
describe('instrumentation/decorator', () => {
|
||||
const spy = jest.fn(() => Promise.resolve());
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should instrument async function', async () => {
|
||||
class MyClass {
|
||||
@instrument({ name: 'getNumber' })
|
||||
public async getNumber(): Promise<number> {
|
||||
await spy();
|
||||
return Math.random();
|
||||
}
|
||||
}
|
||||
const myClass = new MyClass();
|
||||
const result = await myClass.getNumber();
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toBeNumber();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should instrument multiple async function calls', async () => {
|
||||
class MyClass {
|
||||
@instrument({ name: 'getNumber' })
|
||||
public async getNumber(): Promise<number> {
|
||||
await spy();
|
||||
return Math.random();
|
||||
}
|
||||
}
|
||||
const myClass = new MyClass();
|
||||
await myClass.getNumber();
|
||||
await myClass.getNumber();
|
||||
const result = await myClass.getNumber();
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toBeNumber();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
21
lib/instrumentation/decorator.ts
Normal file
21
lib/instrumentation/decorator.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { Decorator, decorate } from '../util/decorator';
|
||||
import type { SpanParameters } from './types';
|
||||
import { instrument as instrumentFunc } from '.';
|
||||
|
||||
/**
|
||||
* instruments a decorated method.
|
||||
*/
|
||||
export function instrument<T>({
|
||||
name,
|
||||
attributes,
|
||||
ignoreParentSpan,
|
||||
kind,
|
||||
}: SpanParameters): Decorator<T> {
|
||||
return decorate(async ({ callback }) => {
|
||||
return await instrumentFunc(name, callback, {
|
||||
attributes,
|
||||
root: ignoreParentSpan,
|
||||
kind,
|
||||
});
|
||||
});
|
||||
}
|
121
lib/instrumentation/index.spec.ts
Normal file
121
lib/instrumentation/index.spec.ts
Normal file
|
@ -0,0 +1,121 @@
|
|||
import { afterAll } from '@jest/globals';
|
||||
import { ProxyTracerProvider } from '@opentelemetry/api';
|
||||
import * as api from '@opentelemetry/api';
|
||||
import { NoopTracerProvider } from '@opentelemetry/api/build/src/trace/NoopTracerProvider';
|
||||
import { MultiSpanProcessor } from '@opentelemetry/sdk-trace-base/build/src/MultiSpanProcessor';
|
||||
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
||||
import {
|
||||
disableInstrumentations,
|
||||
getTracerProvider,
|
||||
init,
|
||||
instrument,
|
||||
} from '.';
|
||||
|
||||
afterAll(disableInstrumentations);
|
||||
|
||||
describe('instrumentation/index', () => {
|
||||
const oldEnv = process.env;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
api.trace.disable(); // clear global components
|
||||
process.env = { ...oldEnv };
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
process.env = oldEnv; // Restore old environment
|
||||
});
|
||||
|
||||
it('should use NoopTraceProvider if not activated', () => {
|
||||
init();
|
||||
const traceProvider = getTracerProvider();
|
||||
expect(traceProvider).toBeInstanceOf(ProxyTracerProvider);
|
||||
const provider = traceProvider as ProxyTracerProvider;
|
||||
expect(provider.getDelegate()).toBeInstanceOf(NoopTracerProvider);
|
||||
});
|
||||
|
||||
it('activate console logger', () => {
|
||||
process.env.RENOVATE_TRACING_CONSOLE_EXPORTER = 'true';
|
||||
|
||||
init();
|
||||
const traceProvider = getTracerProvider();
|
||||
expect(traceProvider).toBeInstanceOf(ProxyTracerProvider);
|
||||
const proxyProvider = traceProvider as ProxyTracerProvider;
|
||||
const delegateProvider = proxyProvider.getDelegate();
|
||||
expect(delegateProvider).toBeInstanceOf(NodeTracerProvider);
|
||||
const nodeProvider = delegateProvider as NodeTracerProvider;
|
||||
const provider = nodeProvider.getActiveSpanProcessor();
|
||||
expect(provider).toBeInstanceOf(MultiSpanProcessor);
|
||||
expect(provider).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('activate remote logger', () => {
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'https://collector.example.com';
|
||||
|
||||
init();
|
||||
const traceProvider = getTracerProvider();
|
||||
expect(traceProvider).toBeInstanceOf(ProxyTracerProvider);
|
||||
const proxyProvider = traceProvider as ProxyTracerProvider;
|
||||
const delegateProvider = proxyProvider.getDelegate();
|
||||
expect(delegateProvider).toBeInstanceOf(NodeTracerProvider);
|
||||
const nodeProvider = delegateProvider as NodeTracerProvider;
|
||||
const provider = nodeProvider.getActiveSpanProcessor();
|
||||
expect(provider).toBeInstanceOf(MultiSpanProcessor);
|
||||
expect(provider).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('activate console logger and remote logger', () => {
|
||||
process.env.RENOVATE_TRACING_CONSOLE_EXPORTER = 'true';
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'https://collector.example.com';
|
||||
|
||||
init();
|
||||
const traceProvider = getTracerProvider();
|
||||
expect(traceProvider).toBeInstanceOf(ProxyTracerProvider);
|
||||
const proxyProvider = traceProvider as ProxyTracerProvider;
|
||||
const delegateProvider = proxyProvider.getDelegate();
|
||||
expect(delegateProvider).toBeInstanceOf(NodeTracerProvider);
|
||||
const nodeProvider = delegateProvider as NodeTracerProvider;
|
||||
const provider = nodeProvider.getActiveSpanProcessor();
|
||||
expect(provider).toBeInstanceOf(MultiSpanProcessor);
|
||||
expect(provider).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('instrument', () => {
|
||||
it('should return result', () => {
|
||||
const value = 'testResult';
|
||||
const result = instrument('test', () => {
|
||||
return value;
|
||||
});
|
||||
expect(result).toStrictEqual(value);
|
||||
});
|
||||
|
||||
it('should rethrow exception', () => {
|
||||
const error = new Error('testError');
|
||||
expect(() =>
|
||||
instrument('test', () => {
|
||||
throw error;
|
||||
})
|
||||
).toThrow(error);
|
||||
});
|
||||
|
||||
it('should return result for async fn', async () => {
|
||||
const value = 'testResult';
|
||||
const result = await instrument('test', async () => {
|
||||
return await new Promise((resolve) => {
|
||||
resolve(value);
|
||||
});
|
||||
});
|
||||
expect(result).toStrictEqual(value);
|
||||
});
|
||||
|
||||
it('should rethrow exception for async fn', async () => {
|
||||
const error = new Error('testError');
|
||||
await expect(
|
||||
instrument('test', async () => {
|
||||
await Promise.resolve();
|
||||
throw error;
|
||||
})
|
||||
).rejects.toThrow(error);
|
||||
});
|
||||
});
|
||||
});
|
165
lib/instrumentation/index.ts
Normal file
165
lib/instrumentation/index.ts
Normal file
|
@ -0,0 +1,165 @@
|
|||
import { ClientRequest } from 'http';
|
||||
import type {
|
||||
Context,
|
||||
Span,
|
||||
SpanOptions,
|
||||
Tracer,
|
||||
TracerProvider,
|
||||
} from '@opentelemetry/api';
|
||||
import * as api from '@opentelemetry/api';
|
||||
import { ProxyTracerProvider, SpanStatusCode } from '@opentelemetry/api';
|
||||
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
|
||||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
||||
import {
|
||||
Instrumentation,
|
||||
registerInstrumentations,
|
||||
} from '@opentelemetry/instrumentation';
|
||||
import { BunyanInstrumentation } from '@opentelemetry/instrumentation-bunyan';
|
||||
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
||||
import { Resource } from '@opentelemetry/resources';
|
||||
import {
|
||||
BatchSpanProcessor,
|
||||
ConsoleSpanExporter,
|
||||
SimpleSpanProcessor,
|
||||
} from '@opentelemetry/sdk-trace-base';
|
||||
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
||||
import { pkg } from '../expose.cjs';
|
||||
import {
|
||||
isTraceDebuggingEnabled,
|
||||
isTraceSendingEnabled,
|
||||
isTracingEnabled,
|
||||
} from './utils';
|
||||
|
||||
let instrumentations: Instrumentation[] = [];
|
||||
|
||||
init();
|
||||
|
||||
export function init(): void {
|
||||
if (!isTracingEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const traceProvider = new NodeTracerProvider({
|
||||
resource: new Resource({
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#semantic-attributes-with-sdk-provided-default-value
|
||||
[SemanticResourceAttributes.SERVICE_NAME]: 'renovate',
|
||||
[SemanticResourceAttributes.SERVICE_NAMESPACE]: 'renovatebot.com',
|
||||
[SemanticResourceAttributes.SERVICE_VERSION]: pkg.version,
|
||||
}),
|
||||
});
|
||||
|
||||
// add processors
|
||||
if (isTraceDebuggingEnabled()) {
|
||||
traceProvider.addSpanProcessor(
|
||||
new SimpleSpanProcessor(new ConsoleSpanExporter())
|
||||
);
|
||||
}
|
||||
|
||||
// OTEL specification environment variable
|
||||
if (isTraceSendingEnabled()) {
|
||||
const exporter = new OTLPTraceExporter();
|
||||
traceProvider.addSpanProcessor(new BatchSpanProcessor(exporter));
|
||||
}
|
||||
|
||||
const contextManager = new AsyncLocalStorageContextManager();
|
||||
traceProvider.register({
|
||||
contextManager,
|
||||
});
|
||||
|
||||
instrumentations = [
|
||||
new HttpInstrumentation({
|
||||
applyCustomAttributesOnSpan: /* istanbul ignore next */ (
|
||||
span,
|
||||
request,
|
||||
response
|
||||
) => {
|
||||
// ignore 404 errors when the branch protection of Github could not be found. This is expected if no rules are configured
|
||||
if (
|
||||
request instanceof ClientRequest &&
|
||||
request.host === `api.github.com` &&
|
||||
request.path.endsWith(`/protection`) &&
|
||||
response.statusCode === 404
|
||||
) {
|
||||
span.setStatus({ code: SpanStatusCode.OK });
|
||||
}
|
||||
},
|
||||
}),
|
||||
new BunyanInstrumentation(),
|
||||
];
|
||||
registerInstrumentations({
|
||||
instrumentations,
|
||||
});
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
|
||||
// https://github.com/open-telemetry/opentelemetry-js-api/issues/34
|
||||
export async function shutdown(): Promise<void> {
|
||||
const traceProvider = getTracerProvider();
|
||||
if (traceProvider instanceof NodeTracerProvider) {
|
||||
await traceProvider.shutdown();
|
||||
} else if (traceProvider instanceof ProxyTracerProvider) {
|
||||
const delegateProvider = traceProvider.getDelegate();
|
||||
if (delegateProvider instanceof NodeTracerProvider) {
|
||||
await delegateProvider.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function disableInstrumentations(): void {
|
||||
for (const instrumentation of instrumentations) {
|
||||
instrumentation.disable();
|
||||
}
|
||||
}
|
||||
|
||||
export function getTracerProvider(): TracerProvider {
|
||||
return api.trace.getTracerProvider();
|
||||
}
|
||||
|
||||
function getTracer(): Tracer {
|
||||
return getTracerProvider().getTracer('renovate');
|
||||
}
|
||||
|
||||
export function instrument<F extends (span: Span) => ReturnType<F>>(
|
||||
name: string,
|
||||
fn: F
|
||||
): ReturnType<F>;
|
||||
export function instrument<F extends (span: Span) => ReturnType<F>>(
|
||||
name: string,
|
||||
fn: F,
|
||||
options: SpanOptions
|
||||
): ReturnType<F>;
|
||||
export function instrument<F extends (span: Span) => ReturnType<F>>(
|
||||
name: string,
|
||||
fn: F,
|
||||
options: SpanOptions = {},
|
||||
context: Context = api.context.active()
|
||||
): ReturnType<F> {
|
||||
return getTracer().startActiveSpan(name, options, context, (span: Span) => {
|
||||
try {
|
||||
const ret = fn(span);
|
||||
if (ret instanceof Promise) {
|
||||
return ret
|
||||
.catch((e) => {
|
||||
span.setStatus({
|
||||
code: SpanStatusCode.ERROR,
|
||||
message: e,
|
||||
});
|
||||
throw e;
|
||||
})
|
||||
.finally(() => span.end()) as ReturnType<F>;
|
||||
}
|
||||
span.end();
|
||||
return ret;
|
||||
} catch (e) {
|
||||
span.setStatus({
|
||||
code: SpanStatusCode.ERROR,
|
||||
message: e,
|
||||
});
|
||||
span.end();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
26
lib/instrumentation/types.ts
Normal file
26
lib/instrumentation/types.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import type { Attributes, SpanKind } from '@opentelemetry/api';
|
||||
|
||||
/**
|
||||
* The instrumentation decorator parameters.
|
||||
*/
|
||||
export interface SpanParameters {
|
||||
/**
|
||||
* The name of the span
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Attributes which should be added to the span
|
||||
*/
|
||||
attributes?: Attributes;
|
||||
|
||||
/**
|
||||
* Should this span be added to the root span or to the current active span
|
||||
*/
|
||||
ignoreParentSpan?: boolean;
|
||||
|
||||
/**
|
||||
* Type of span this represents. Default: SpanKind.Internal
|
||||
*/
|
||||
kind?: SpanKind;
|
||||
}
|
11
lib/instrumentation/utils.ts
Normal file
11
lib/instrumentation/utils.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export function isTracingEnabled(): boolean {
|
||||
return isTraceDebuggingEnabled() || isTraceSendingEnabled();
|
||||
}
|
||||
|
||||
export function isTraceDebuggingEnabled(): boolean {
|
||||
return !!process.env.RENOVATE_TRACING_CONSOLE_EXPORTER;
|
||||
}
|
||||
|
||||
export function isTraceSendingEnabled(): boolean {
|
||||
return !!process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { instrument, shutdown as telemetryShutdown } from './instrumentation'; // has to be imported before logger and other libraries which are instrumentalised
|
||||
import { logger } from './logger';
|
||||
import * as proxy from './proxy';
|
||||
import * as globalWorker from './workers/global';
|
||||
|
@ -13,7 +14,9 @@ proxy.bootstrap();
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
(async (): Promise<void> => {
|
||||
process.exitCode = await globalWorker.start();
|
||||
process.exitCode = await instrument('run', () => globalWorker.start());
|
||||
await telemetryShutdown(); //gracefully shutdown OpenTelemetry
|
||||
|
||||
// istanbul ignore if
|
||||
if (process.env.RENOVATE_X_HARD_EXIT) {
|
||||
process.exit(process.exitCode);
|
||||
|
|
|
@ -15,6 +15,7 @@ import type {
|
|||
} from '../../config/types';
|
||||
import { CONFIG_PRESETS_INVALID } from '../../constants/error-messages';
|
||||
import { pkg } from '../../expose.cjs';
|
||||
import { instrument } from '../../instrumentation';
|
||||
import { getProblems, logger, setMeta } from '../../logger';
|
||||
import * as hostRules from '../../util/host-rules';
|
||||
import * as queue from '../../util/http/queue';
|
||||
|
@ -107,30 +108,37 @@ export async function resolveGlobalExtends(
|
|||
export async function start(): Promise<number> {
|
||||
let config: AllConfig;
|
||||
try {
|
||||
// read global config from file, env and cli args
|
||||
config = await getGlobalConfig();
|
||||
if (config?.globalExtends) {
|
||||
// resolve global presets immediately
|
||||
config = mergeChildConfig(
|
||||
config,
|
||||
await resolveGlobalExtends(config.globalExtends)
|
||||
);
|
||||
}
|
||||
// initialize all submodules
|
||||
config = await globalInitialize(config);
|
||||
await instrument('config', async () => {
|
||||
// read global config from file, env and cli args
|
||||
config = await getGlobalConfig();
|
||||
if (config?.globalExtends) {
|
||||
// resolve global presets immediately
|
||||
config = mergeChildConfig(
|
||||
config,
|
||||
await resolveGlobalExtends(config.globalExtends)
|
||||
);
|
||||
}
|
||||
// initialize all submodules
|
||||
config = await globalInitialize(config);
|
||||
|
||||
// Set platform and endpoint in case local presets are used
|
||||
GlobalConfig.set({ platform: config.platform, endpoint: config.endpoint });
|
||||
// Set platform and endpoint in case local presets are used
|
||||
GlobalConfig.set({
|
||||
platform: config.platform,
|
||||
endpoint: config.endpoint,
|
||||
});
|
||||
|
||||
await validatePresets(config);
|
||||
await validatePresets(config);
|
||||
|
||||
checkEnv();
|
||||
checkEnv();
|
||||
|
||||
// validate secrets. Will throw and abort if invalid
|
||||
validateConfigSecrets(config);
|
||||
// validate secrets. Will throw and abort if invalid
|
||||
validateConfigSecrets(config);
|
||||
});
|
||||
|
||||
// autodiscover repositories (needs to come after platform initialization)
|
||||
config = await autodiscoverRepositories(config);
|
||||
config = await instrument('discover', () =>
|
||||
autodiscoverRepositories(config)
|
||||
);
|
||||
|
||||
if (is.nonEmptyString(config.writeDiscoveredRepos)) {
|
||||
const content = JSON.stringify(config.repositories);
|
||||
|
@ -146,19 +154,32 @@ export async function start(): Promise<number> {
|
|||
if (haveReachedLimits()) {
|
||||
break;
|
||||
}
|
||||
const repoConfig = await getRepositoryConfig(config, repository);
|
||||
if (repoConfig.hostRules) {
|
||||
logger.debug('Reinitializing hostRules for repo');
|
||||
hostRules.clear();
|
||||
repoConfig.hostRules.forEach((rule) => hostRules.add(rule));
|
||||
repoConfig.hostRules = [];
|
||||
}
|
||||
await instrument(
|
||||
'repository',
|
||||
async () => {
|
||||
const repoConfig = await getRepositoryConfig(config, repository);
|
||||
if (repoConfig.hostRules) {
|
||||
logger.debug('Reinitializing hostRules for repo');
|
||||
hostRules.clear();
|
||||
repoConfig.hostRules.forEach((rule) => hostRules.add(rule));
|
||||
repoConfig.hostRules = [];
|
||||
}
|
||||
|
||||
// host rules can change concurrency
|
||||
queue.clear();
|
||||
// host rules can change concurrency
|
||||
queue.clear();
|
||||
|
||||
await repositoryWorker.renovateRepository(repoConfig);
|
||||
setMeta({});
|
||||
await repositoryWorker.renovateRepository(repoConfig);
|
||||
setMeta({});
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
repository:
|
||||
typeof repository === 'string'
|
||||
? repository
|
||||
: repository.repository,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (err) /* istanbul ignore next */ {
|
||||
if (err.message.startsWith('Init: ')) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { GlobalConfig } from '../../config/global';
|
|||
import { applySecretsToConfig } from '../../config/secrets';
|
||||
import type { RenovateConfig } from '../../config/types';
|
||||
import { pkg } from '../../expose.cjs';
|
||||
import { instrument } from '../../instrumentation';
|
||||
import { logger, setMeta } from '../../logger';
|
||||
import { removeDanglingContainers } from '../../util/exec/docker';
|
||||
import { deleteLocalFile, privateCacheDir } from '../../util/fs';
|
||||
|
@ -42,16 +43,22 @@ export async function renovateRepository(
|
|||
logger.debug('Using localDir: ' + localDir);
|
||||
config = await initRepo(config);
|
||||
addSplit('init');
|
||||
const { branches, branchList, packageFiles } = await extractDependencies(
|
||||
config
|
||||
const { branches, branchList, packageFiles } = await instrument(
|
||||
'extract',
|
||||
() => extractDependencies(config)
|
||||
);
|
||||
if (
|
||||
GlobalConfig.get('dryRun') !== 'lookup' &&
|
||||
GlobalConfig.get('dryRun') !== 'extract'
|
||||
) {
|
||||
await ensureOnboardingPr(config, packageFiles, branches);
|
||||
await instrument('onboarding', () =>
|
||||
ensureOnboardingPr(config, packageFiles, branches)
|
||||
);
|
||||
addSplit('onboarding');
|
||||
const res = await updateRepo(config, branches);
|
||||
|
||||
const res = await instrument('update', () =>
|
||||
updateRepo(config, branches)
|
||||
);
|
||||
setMeta({ repository: config.repository });
|
||||
addSplit('update');
|
||||
await setBranchCache(branches);
|
||||
|
|
10
package.json
10
package.json
|
@ -145,6 +145,16 @@
|
|||
"@cheap-glitch/mi-cron": "1.0.1",
|
||||
"@iarna/toml": "2.2.5",
|
||||
"@renovatebot/osv-offline": "1.0.5",
|
||||
"@opentelemetry/api": "1.2.0",
|
||||
"@opentelemetry/context-async-hooks": "1.6.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "0.32.0",
|
||||
"@opentelemetry/instrumentation": "0.32.0",
|
||||
"@opentelemetry/instrumentation-bunyan": "0.29.0",
|
||||
"@opentelemetry/instrumentation-http": "0.32.0",
|
||||
"@opentelemetry/resources": "1.6.0",
|
||||
"@opentelemetry/sdk-trace-base": "1.6.0",
|
||||
"@opentelemetry/sdk-trace-node": "1.6.0",
|
||||
"@opentelemetry/semantic-conventions": "1.6.0",
|
||||
"@renovatebot/pep440": "2.1.5",
|
||||
"@renovatebot/ruby-semver": "1.1.6",
|
||||
"@sindresorhus/is": "4.6.0",
|
||||
|
|
192
yarn.lock
192
yarn.lock
|
@ -2313,10 +2313,172 @@
|
|||
resolved "https://registry.yarnpkg.com/@openpgp/web-stream-tools/-/web-stream-tools-0.0.12.tgz#8a80170c7590ecee2af4220c5cb1efe1a02946eb"
|
||||
integrity sha512-OGQ7a7UlALBOPxTWqLjPoa6YjHtLYF5ETb3zwx2A2Qq3YsstJX4q/OvYx60v2MavmBBJELsBQNugdJu0uMBhSw==
|
||||
|
||||
"@opentelemetry/api-metrics@0.29.2":
|
||||
version "0.29.2"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.29.2.tgz#daa823e0965754222b49a6ae6133df8b39ff8fd2"
|
||||
integrity sha512-yRdF5beqKuEdsPNoO7ijWCQ9HcyN0Tlgicf8RS6gzGOI54d6Hj7yKquJ6+X9XV+CSRbRWJYb+lOsXyso7uyX2g==
|
||||
dependencies:
|
||||
"@opentelemetry/api" "^1.0.0"
|
||||
|
||||
"@opentelemetry/api-metrics@0.32.0":
|
||||
version "0.32.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.32.0.tgz#0f09f78491a4b301ddf54a8b8a38ffa99981f645"
|
||||
integrity sha512-g1WLhpG8B6iuDyZJFRGsR+JKyZ94m5LEmY2f+duEJ9Xb4XRlLHrZvh6G34OH6GJ8iDHxfHb/sWjJ1ZpkI9yGMQ==
|
||||
dependencies:
|
||||
"@opentelemetry/api" "^1.0.0"
|
||||
|
||||
"@opentelemetry/api@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.2.0.tgz#89ef99401cde6208cff98760b67663726ef26686"
|
||||
integrity sha512-0nBr+VZNKm9tvNDZFstI3Pq1fCTEDK5OZTnVKNvBNAKgd0yIvmwsP4m61rEv7ZP+tOUjWJhROpxK5MsnlF911g==
|
||||
|
||||
"@opentelemetry/api@^1.0.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.1.0.tgz#563539048255bbe1a5f4f586a4a10a1bb737f44a"
|
||||
integrity sha512-hf+3bwuBwtXsugA2ULBc95qxrOqP2pOekLz34BJhcAKawt94vfeNyUKpYc0lZQ/3sCP6LqRa7UAdHA7i5UODzQ==
|
||||
|
||||
"@opentelemetry/context-async-hooks@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.6.0.tgz#e3839bf8c010d7e660d9762fe2407171d352b88e"
|
||||
integrity sha512-7xpyfHfuHnuCm5eAk4j4MIZjRM/hsiLlKEFIwI8SXNlbxqmb/JRrntOjN/AT+KeihkMw+xAx+0lsYPUANCSaQw==
|
||||
|
||||
"@opentelemetry/core@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.6.0.tgz#c55f8ab7496acef7dbd8c4eedef6a4d4a0143c95"
|
||||
integrity sha512-MsEhsyCTfYme6frK8/AqEWwbS9SB3Ta5bjgz4jPQJjL7ijUM3JiLVvqh/kHo1UlUjbUbLmGG7jA5Nw4d7SMcLQ==
|
||||
dependencies:
|
||||
"@opentelemetry/semantic-conventions" "1.6.0"
|
||||
|
||||
"@opentelemetry/exporter-trace-otlp-http@0.32.0":
|
||||
version "0.32.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.32.0.tgz#55773290a221855c4e8c422e8fb5e7ff4aa5f04e"
|
||||
integrity sha512-8n44NDoEFoYG3mMToZxNyUKkHSGfzSShw6I2V5FApcH7rid20LmKiNuzc7lACneDIZBld+GGpLRuFhWniW8JhA==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
"@opentelemetry/otlp-exporter-base" "0.32.0"
|
||||
"@opentelemetry/otlp-transformer" "0.32.0"
|
||||
"@opentelemetry/resources" "1.6.0"
|
||||
"@opentelemetry/sdk-trace-base" "1.6.0"
|
||||
|
||||
"@opentelemetry/instrumentation-bunyan@0.29.0":
|
||||
version "0.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.29.0.tgz#04132ef917e39200d76331e32b36a968bafbfbd3"
|
||||
integrity sha512-i1FZ+W96vQCIpkMKPZW0HOA79ve9PLIcTAFH0adU/CvtRRMSxyKPTKzWMGHcWr6DueKIPEorpMG+nO2Z/yk9iQ==
|
||||
dependencies:
|
||||
"@opentelemetry/instrumentation" "^0.29.2"
|
||||
"@types/bunyan" "1.8.7"
|
||||
|
||||
"@opentelemetry/instrumentation-http@0.32.0":
|
||||
version "0.32.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.32.0.tgz#63ea9e3a3d114a7e3f922e3a39b57afa874e6478"
|
||||
integrity sha512-EbNdJl6IjouphbxPVGV8/utiqB2DhveyH5TD6vxjc2OXlQ3A/mKg3fYSSWB+rYQBuuli+jWQfBJe2ntOFZtTMw==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
"@opentelemetry/instrumentation" "0.32.0"
|
||||
"@opentelemetry/semantic-conventions" "1.6.0"
|
||||
semver "^7.3.5"
|
||||
|
||||
"@opentelemetry/instrumentation@0.32.0":
|
||||
version "0.32.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.32.0.tgz#27c5975a323a2ba83d9bf2ea8b11faaab37c5827"
|
||||
integrity sha512-y6ADjHpkUz/v1nkyyYjsQa/zorhX+0qVGpFvXMcbjU4sHnBnC02c6wcc93sIgZfiQClIWo45TGku1KQxJ5UUbQ==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.32.0"
|
||||
require-in-the-middle "^5.0.3"
|
||||
semver "^7.3.2"
|
||||
shimmer "^1.2.1"
|
||||
|
||||
"@opentelemetry/instrumentation@^0.29.2":
|
||||
version "0.29.2"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.29.2.tgz#70e6d4e1a84508f5e9d8c7c426adcd7b0dba6c95"
|
||||
integrity sha512-LXx5V0ONNATQFCE8C5uqnxWSm4rcXLssdLHdXjtGdxRmURqj/JO8jYefqXCD0LzsqEQ6yxOx2GZ0dgXvhBVdTw==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.29.2"
|
||||
require-in-the-middle "^5.0.3"
|
||||
semver "^7.3.2"
|
||||
shimmer "^1.2.1"
|
||||
|
||||
"@opentelemetry/otlp-exporter-base@0.32.0":
|
||||
version "0.32.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.32.0.tgz#37dde162835a8fd23fa040f07e2938deb335fc4b"
|
||||
integrity sha512-Dscxu4VNKrkD1SwGKdc7bAtLViGFJC8ah6Dr/vZn22NFHXSa53lSzDdTKeSTNNWH9sCGu/65LS45VMd4PsRvwQ==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
|
||||
"@opentelemetry/otlp-transformer@0.32.0":
|
||||
version "0.32.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.32.0.tgz#652c8f4c56c95f7d7ec39e20573b885d27ca13f1"
|
||||
integrity sha512-PFAqfKgJpTOZryPe1UMm7R578PLxsK0wCAuKSt6m8v1bN/4DO8DX4HD7k3mYGZVU5jNg8tVZSwyIpY6ryrHDMQ==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.32.0"
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
"@opentelemetry/resources" "1.6.0"
|
||||
"@opentelemetry/sdk-metrics" "0.32.0"
|
||||
"@opentelemetry/sdk-trace-base" "1.6.0"
|
||||
|
||||
"@opentelemetry/propagator-b3@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-1.6.0.tgz#db0dee4f28cb4f1830f3cd35013b652b8078f355"
|
||||
integrity sha512-azs3aCIFrr3qkA/6lNIAYJ+wgDQ6cFoyeHVcZXP0E96AiOeVqtAu5ZXSA63Cw/63pSw0Itmx6CHUGu41enc0TQ==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
|
||||
"@opentelemetry/propagator-jaeger@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.6.0.tgz#e3e910d71967efb7923674ac407b14c117ea7f31"
|
||||
integrity sha512-QgvWVgRS+APP7aHGPHgKo7HXJg2BbwW394kDNW1HeIxrywliUdAk8h5SJ/VGehy/dTzCFwbDd5Y3TMQRUNCHDg==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
|
||||
"@opentelemetry/resources@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.6.0.tgz#9756894131b9b0dfbcc0cecb5d4bd040d9c1b09d"
|
||||
integrity sha512-07GlHuq72r2rnJugYVdGumviQvfrl8kEPidkZSVoseLVfIjV7nzxxt5/vqs9pK7JItWOrvjRdr/jTBVayFBr/w==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
"@opentelemetry/semantic-conventions" "1.6.0"
|
||||
|
||||
"@opentelemetry/sdk-metrics@0.32.0":
|
||||
version "0.32.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-0.32.0.tgz#463cd3a2b267f044db9aaab85887a171710345a0"
|
||||
integrity sha512-zC9RCOIsXRqOHWmWfcxArtDHbip2/jaIH1yu/OKau/shDZYFluAxY6zAEYIb4YEAzKKEF+fpaoRgpodDWNGVGA==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.32.0"
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
"@opentelemetry/resources" "1.6.0"
|
||||
lodash.merge "4.6.2"
|
||||
|
||||
"@opentelemetry/sdk-trace-base@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.6.0.tgz#8b1511c0b0f3e6015e345f5ed4a683adf03e3e3c"
|
||||
integrity sha512-yx/uuzHdT0QNRSEbCgXHc0GONk90uvaFcPGaNowIFSl85rTp4or4uIIMkG7R8ckj8xWjDSjsaztH6yQxoZrl5g==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
"@opentelemetry/resources" "1.6.0"
|
||||
"@opentelemetry/semantic-conventions" "1.6.0"
|
||||
|
||||
"@opentelemetry/sdk-trace-node@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.6.0.tgz#fb15e030b19931f1cd6ad755add2bfd77fb915b6"
|
||||
integrity sha512-rE6hL68QuSS2vDXZBhNiAkeN7kzDGrrJdzGeeyxQahmugnId5jmu1OYERIeULiKHQVkBjvycfmwPYsCL+3PsHQ==
|
||||
dependencies:
|
||||
"@opentelemetry/context-async-hooks" "1.6.0"
|
||||
"@opentelemetry/core" "1.6.0"
|
||||
"@opentelemetry/propagator-b3" "1.6.0"
|
||||
"@opentelemetry/propagator-jaeger" "1.6.0"
|
||||
"@opentelemetry/sdk-trace-base" "1.6.0"
|
||||
semver "^7.3.5"
|
||||
|
||||
"@opentelemetry/semantic-conventions@1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.6.0.tgz#ed410c9eb0070491cff9fe914246ce41f88d6f74"
|
||||
integrity sha512-aPfcBeLErM/PPiAuAbNFLN5sNbZLc3KZlar27uohllN8Zs6jJbHyJU1y7cMA6W/zuq+thkaG8mujiS+3iD/FWQ==
|
||||
|
||||
"@pkgr/utils@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.3.1.tgz#0a9b06ffddee364d6642b3cd562ca76f55b34a03"
|
||||
integrity sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==
|
||||
|
||||
dependencies:
|
||||
cross-spawn "^7.0.3"
|
||||
is-glob "^4.0.3"
|
||||
|
@ -2733,6 +2895,13 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.3.0"
|
||||
|
||||
"@types/bunyan@1.8.7":
|
||||
version "1.8.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/bunyan/-/bunyan-1.8.7.tgz#63cc65b5ecff6217d1509409a575e7b991f80831"
|
||||
integrity sha512-jaNt6xX5poSmXuDAkQrSqx2zkR66OrdRDuVnU8ldvn3k/Ci/7Sf5nooKspQWimDnw337Bzt/yirqSThTjvrHkg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/bunyan@1.8.8":
|
||||
version "1.8.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/bunyan/-/bunyan-1.8.8.tgz#8d6d33f090f37c07e2a80af30ae728450a101008"
|
||||
|
@ -7208,7 +7377,7 @@ lodash.memoize@4.x:
|
|||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
|
||||
|
||||
lodash.merge@^4.6.2:
|
||||
lodash.merge@4.6.2, lodash.merge@^4.6.2:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||
|
@ -7649,6 +7818,11 @@ modify-values@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
|
||||
integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
|
||||
|
||||
module-details-from-path@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b"
|
||||
integrity sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=
|
||||
|
||||
moment@^2.19.3:
|
||||
version "2.29.4"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||
|
@ -8897,6 +9071,15 @@ require-directory@^2.1.1:
|
|||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
|
||||
|
||||
require-in-the-middle@^5.0.3:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz#b768f800377b47526d026bbf5a7f727f16eb412f"
|
||||
integrity sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
module-details-from-path "^1.0.3"
|
||||
resolve "^1.12.0"
|
||||
|
||||
resolve-alpn@^1.0.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
|
||||
|
@ -8924,7 +9107,7 @@ resolve.exports@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9"
|
||||
integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==
|
||||
|
||||
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.0:
|
||||
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.20.0, resolve@^1.22.0:
|
||||
version "1.22.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||
|
@ -9157,6 +9340,11 @@ shelljs@0.8.5:
|
|||
interpret "^1.0.0"
|
||||
rechoir "^0.6.2"
|
||||
|
||||
shimmer@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337"
|
||||
integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==
|
||||
|
||||
shlex@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/shlex/-/shlex-2.1.2.tgz#5b5384d603885281c1dee05d56975865edddcba0"
|
||||
|
|
Loading…
Reference in a new issue