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`
|
## `RENOVATE_X_EXEC_GPID_HANDLE`
|
||||||
|
|
||||||
If set, Renovate will terminate the whole process group of a terminated child process spawned by Renovate.
|
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
|
#!/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 { logger } from './logger';
|
||||||
import * as proxy from './proxy';
|
import * as proxy from './proxy';
|
||||||
import * as globalWorker from './workers/global';
|
import * as globalWorker from './workers/global';
|
||||||
|
@ -13,7 +14,9 @@ proxy.bootstrap();
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
(async (): Promise<void> => {
|
(async (): Promise<void> => {
|
||||||
process.exitCode = await globalWorker.start();
|
process.exitCode = await instrument('run', () => globalWorker.start());
|
||||||
|
await telemetryShutdown(); //gracefully shutdown OpenTelemetry
|
||||||
|
|
||||||
// istanbul ignore if
|
// istanbul ignore if
|
||||||
if (process.env.RENOVATE_X_HARD_EXIT) {
|
if (process.env.RENOVATE_X_HARD_EXIT) {
|
||||||
process.exit(process.exitCode);
|
process.exit(process.exitCode);
|
||||||
|
|
|
@ -15,6 +15,7 @@ import type {
|
||||||
} from '../../config/types';
|
} from '../../config/types';
|
||||||
import { CONFIG_PRESETS_INVALID } from '../../constants/error-messages';
|
import { CONFIG_PRESETS_INVALID } from '../../constants/error-messages';
|
||||||
import { pkg } from '../../expose.cjs';
|
import { pkg } from '../../expose.cjs';
|
||||||
|
import { instrument } from '../../instrumentation';
|
||||||
import { getProblems, logger, setMeta } from '../../logger';
|
import { getProblems, logger, setMeta } from '../../logger';
|
||||||
import * as hostRules from '../../util/host-rules';
|
import * as hostRules from '../../util/host-rules';
|
||||||
import * as queue from '../../util/http/queue';
|
import * as queue from '../../util/http/queue';
|
||||||
|
@ -107,6 +108,7 @@ export async function resolveGlobalExtends(
|
||||||
export async function start(): Promise<number> {
|
export async function start(): Promise<number> {
|
||||||
let config: AllConfig;
|
let config: AllConfig;
|
||||||
try {
|
try {
|
||||||
|
await instrument('config', async () => {
|
||||||
// read global config from file, env and cli args
|
// read global config from file, env and cli args
|
||||||
config = await getGlobalConfig();
|
config = await getGlobalConfig();
|
||||||
if (config?.globalExtends) {
|
if (config?.globalExtends) {
|
||||||
|
@ -120,7 +122,10 @@ export async function start(): Promise<number> {
|
||||||
config = await globalInitialize(config);
|
config = await globalInitialize(config);
|
||||||
|
|
||||||
// Set platform and endpoint in case local presets are used
|
// Set platform and endpoint in case local presets are used
|
||||||
GlobalConfig.set({ platform: config.platform, endpoint: config.endpoint });
|
GlobalConfig.set({
|
||||||
|
platform: config.platform,
|
||||||
|
endpoint: config.endpoint,
|
||||||
|
});
|
||||||
|
|
||||||
await validatePresets(config);
|
await validatePresets(config);
|
||||||
|
|
||||||
|
@ -128,9 +133,12 @@ export async function start(): Promise<number> {
|
||||||
|
|
||||||
// validate secrets. Will throw and abort if invalid
|
// validate secrets. Will throw and abort if invalid
|
||||||
validateConfigSecrets(config);
|
validateConfigSecrets(config);
|
||||||
|
});
|
||||||
|
|
||||||
// autodiscover repositories (needs to come after platform initialization)
|
// autodiscover repositories (needs to come after platform initialization)
|
||||||
config = await autodiscoverRepositories(config);
|
config = await instrument('discover', () =>
|
||||||
|
autodiscoverRepositories(config)
|
||||||
|
);
|
||||||
|
|
||||||
if (is.nonEmptyString(config.writeDiscoveredRepos)) {
|
if (is.nonEmptyString(config.writeDiscoveredRepos)) {
|
||||||
const content = JSON.stringify(config.repositories);
|
const content = JSON.stringify(config.repositories);
|
||||||
|
@ -146,6 +154,9 @@ export async function start(): Promise<number> {
|
||||||
if (haveReachedLimits()) {
|
if (haveReachedLimits()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
await instrument(
|
||||||
|
'repository',
|
||||||
|
async () => {
|
||||||
const repoConfig = await getRepositoryConfig(config, repository);
|
const repoConfig = await getRepositoryConfig(config, repository);
|
||||||
if (repoConfig.hostRules) {
|
if (repoConfig.hostRules) {
|
||||||
logger.debug('Reinitializing hostRules for repo');
|
logger.debug('Reinitializing hostRules for repo');
|
||||||
|
@ -159,6 +170,16 @@ export async function start(): Promise<number> {
|
||||||
|
|
||||||
await repositoryWorker.renovateRepository(repoConfig);
|
await repositoryWorker.renovateRepository(repoConfig);
|
||||||
setMeta({});
|
setMeta({});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: {
|
||||||
|
repository:
|
||||||
|
typeof repository === 'string'
|
||||||
|
? repository
|
||||||
|
: repository.repository,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (err) /* istanbul ignore next */ {
|
} catch (err) /* istanbul ignore next */ {
|
||||||
if (err.message.startsWith('Init: ')) {
|
if (err.message.startsWith('Init: ')) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { GlobalConfig } from '../../config/global';
|
||||||
import { applySecretsToConfig } from '../../config/secrets';
|
import { applySecretsToConfig } from '../../config/secrets';
|
||||||
import type { RenovateConfig } from '../../config/types';
|
import type { RenovateConfig } from '../../config/types';
|
||||||
import { pkg } from '../../expose.cjs';
|
import { pkg } from '../../expose.cjs';
|
||||||
|
import { instrument } from '../../instrumentation';
|
||||||
import { logger, setMeta } from '../../logger';
|
import { logger, setMeta } from '../../logger';
|
||||||
import { removeDanglingContainers } from '../../util/exec/docker';
|
import { removeDanglingContainers } from '../../util/exec/docker';
|
||||||
import { deleteLocalFile, privateCacheDir } from '../../util/fs';
|
import { deleteLocalFile, privateCacheDir } from '../../util/fs';
|
||||||
|
@ -42,16 +43,22 @@ export async function renovateRepository(
|
||||||
logger.debug('Using localDir: ' + localDir);
|
logger.debug('Using localDir: ' + localDir);
|
||||||
config = await initRepo(config);
|
config = await initRepo(config);
|
||||||
addSplit('init');
|
addSplit('init');
|
||||||
const { branches, branchList, packageFiles } = await extractDependencies(
|
const { branches, branchList, packageFiles } = await instrument(
|
||||||
config
|
'extract',
|
||||||
|
() => extractDependencies(config)
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
GlobalConfig.get('dryRun') !== 'lookup' &&
|
GlobalConfig.get('dryRun') !== 'lookup' &&
|
||||||
GlobalConfig.get('dryRun') !== 'extract'
|
GlobalConfig.get('dryRun') !== 'extract'
|
||||||
) {
|
) {
|
||||||
await ensureOnboardingPr(config, packageFiles, branches);
|
await instrument('onboarding', () =>
|
||||||
|
ensureOnboardingPr(config, packageFiles, branches)
|
||||||
|
);
|
||||||
addSplit('onboarding');
|
addSplit('onboarding');
|
||||||
const res = await updateRepo(config, branches);
|
|
||||||
|
const res = await instrument('update', () =>
|
||||||
|
updateRepo(config, branches)
|
||||||
|
);
|
||||||
setMeta({ repository: config.repository });
|
setMeta({ repository: config.repository });
|
||||||
addSplit('update');
|
addSplit('update');
|
||||||
await setBranchCache(branches);
|
await setBranchCache(branches);
|
||||||
|
|
10
package.json
10
package.json
|
@ -145,6 +145,16 @@
|
||||||
"@cheap-glitch/mi-cron": "1.0.1",
|
"@cheap-glitch/mi-cron": "1.0.1",
|
||||||
"@iarna/toml": "2.2.5",
|
"@iarna/toml": "2.2.5",
|
||||||
"@renovatebot/osv-offline": "1.0.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/pep440": "2.1.5",
|
||||||
"@renovatebot/ruby-semver": "1.1.6",
|
"@renovatebot/ruby-semver": "1.1.6",
|
||||||
"@sindresorhus/is": "4.6.0",
|
"@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"
|
resolved "https://registry.yarnpkg.com/@openpgp/web-stream-tools/-/web-stream-tools-0.0.12.tgz#8a80170c7590ecee2af4220c5cb1efe1a02946eb"
|
||||||
integrity sha512-OGQ7a7UlALBOPxTWqLjPoa6YjHtLYF5ETb3zwx2A2Qq3YsstJX4q/OvYx60v2MavmBBJELsBQNugdJu0uMBhSw==
|
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":
|
"@pkgr/utils@^2.3.1":
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.3.1.tgz#0a9b06ffddee364d6642b3cd562ca76f55b34a03"
|
resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.3.1.tgz#0a9b06ffddee364d6642b3cd562ca76f55b34a03"
|
||||||
integrity sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==
|
integrity sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn "^7.0.3"
|
cross-spawn "^7.0.3"
|
||||||
is-glob "^4.0.3"
|
is-glob "^4.0.3"
|
||||||
|
@ -2733,6 +2895,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.3.0"
|
"@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":
|
"@types/bunyan@1.8.8":
|
||||||
version "1.8.8"
|
version "1.8.8"
|
||||||
resolved "https://registry.yarnpkg.com/@types/bunyan/-/bunyan-1.8.8.tgz#8d6d33f090f37c07e2a80af30ae728450a101008"
|
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"
|
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
|
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"
|
version "4.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
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"
|
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
|
||||||
integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
|
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:
|
moment@^2.19.3:
|
||||||
version "2.29.4"
|
version "2.29.4"
|
||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
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"
|
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||||
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
|
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:
|
resolve-alpn@^1.0.0:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
|
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"
|
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9"
|
||||||
integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==
|
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"
|
version "1.22.1"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||||
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||||
|
@ -9157,6 +9340,11 @@ shelljs@0.8.5:
|
||||||
interpret "^1.0.0"
|
interpret "^1.0.0"
|
||||||
rechoir "^0.6.2"
|
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:
|
shlex@2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/shlex/-/shlex-2.1.2.tgz#5b5384d603885281c1dee05d56975865edddcba0"
|
resolved "https://registry.yarnpkg.com/shlex/-/shlex-2.1.2.tgz#5b5384d603885281c1dee05d56975865edddcba0"
|
||||||
|
|
Loading…
Reference in a new issue