mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Stack Monitoring] Add OpenTelemetry metrics to Monitoring Collection plugin (#135999)
* Add otel metrics to alerting plugin * clean up otel poc * Bump @opentelemetry/api-metrics and @opentelemetry/exporter-metrics-otlp-grpc versions to 0.30.0 * Add integration test for prometheus endpoint; improve reademe.md * Fix tsconfig.base.json missing entries * Bump @opentelemetry/sdk-metrics-base; clean up * Rename PrometheusExporter properties * Readme formatting tweaks * Fix incorrect path * Remove grpc dependency * Add grpc back for handling auth headers * Fix comment positioning * Include authenticated OTLP in readme * Extract dynamic route into a new file * Enable otlp logging and compatibility with env vars * Enable OTEL_EXPORTER_OTLP_ENDPOINT env var Co-authored-by: Mat Schaffer <mat@elastic.co> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d5ba9cc098
commit
b58d07e05b
29 changed files with 727 additions and 17 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -116,6 +116,7 @@
|
|||
/x-pack/plugins/monitoring/ @elastic/infra-monitoring-ui
|
||||
/x-pack/test/functional/apps/monitoring @elastic/infra-monitoring-ui
|
||||
/x-pack/test/api_integration/apis/monitoring @elastic/infra-monitoring-ui
|
||||
/x-pack/test/api_integration/apis/monitoring_collection @elastic/infra-monitoring-ui
|
||||
|
||||
# Fleet
|
||||
/fleet_packages.json @elastic/fleet
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
"@emotion/css": "^11.9.0",
|
||||
"@emotion/react": "^11.9.0",
|
||||
"@emotion/serialize": "^1.0.3",
|
||||
"@grpc/grpc-js": "^1.6.7",
|
||||
"@hapi/accept": "^5.0.2",
|
||||
"@hapi/boom": "^9.1.4",
|
||||
"@hapi/cookie": "^11.0.2",
|
||||
|
@ -284,6 +285,13 @@
|
|||
"@mapbox/mapbox-gl-draw": "1.3.0",
|
||||
"@mapbox/mapbox-gl-rtl-text": "0.2.3",
|
||||
"@mapbox/vector-tile": "1.3.1",
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
"@opentelemetry/api-metrics": "^0.30.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.30.0",
|
||||
"@opentelemetry/exporter-prometheus": "^0.30.0",
|
||||
"@opentelemetry/resources": "^1.4.0",
|
||||
"@opentelemetry/sdk-metrics-base": "^0.30.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.4.0",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@slack/webhook": "^5.0.4",
|
||||
"@turf/along": "6.0.1",
|
||||
|
|
|
@ -51,6 +51,8 @@ export default function () {
|
|||
`--server.maxPayload=1679958`,
|
||||
// newsfeed mock service
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'newsfeed')}`,
|
||||
// otel mock service
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'otel_metrics')}`,
|
||||
`--newsfeed.service.urlRoot=${servers.kibana.protocol}://${servers.kibana.hostname}:${servers.kibana.port}`,
|
||||
`--newsfeed.service.pathTemplate=/api/_newsfeed-FTS-external-service-simulators/kibana/v{VERSION}.json`,
|
||||
// code coverage reporting plugin
|
||||
|
|
15
test/common/fixtures/plugins/otel_metrics/kibana.json
Normal file
15
test/common/fixtures/plugins/otel_metrics/kibana.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"id": "openTelemetryInstrumentedPlugin",
|
||||
"owner": {
|
||||
"name": "Stack Monitoring",
|
||||
"githubTeam": "stack-monitoring-ui"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"requiredPlugins": [
|
||||
"monitoringCollection"
|
||||
],
|
||||
"optionalPlugins": [],
|
||||
"server": true,
|
||||
"ui": false
|
||||
}
|
11
test/common/fixtures/plugins/otel_metrics/server/index.ts
Normal file
11
test/common/fixtures/plugins/otel_metrics/server/index.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { OpenTelemetryUsageTest } from './plugin';
|
||||
|
||||
export const plugin = () => new OpenTelemetryUsageTest();
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Counter, Meter } from '@opentelemetry/api-metrics';
|
||||
|
||||
export class Metrics {
|
||||
requestCounter: Counter;
|
||||
|
||||
constructor(meter: Meter) {
|
||||
this.requestCounter = meter.createCounter('request_count', {
|
||||
description: 'Counts total number of requests',
|
||||
});
|
||||
}
|
||||
}
|
28
test/common/fixtures/plugins/otel_metrics/server/plugin.ts
Normal file
28
test/common/fixtures/plugins/otel_metrics/server/plugin.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CoreSetup, Plugin } from '@kbn/core/server';
|
||||
import { metrics } from '@opentelemetry/api-metrics';
|
||||
import { generateOtelMetrics } from './routes';
|
||||
import { Metrics } from './monitoring/metrics';
|
||||
|
||||
export class OpenTelemetryUsageTest implements Plugin {
|
||||
private metrics: Metrics;
|
||||
|
||||
constructor() {
|
||||
this.metrics = new Metrics(metrics.getMeter('dummyMetric'));
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup) {
|
||||
const router = core.http.createRouter();
|
||||
generateOtelMetrics(router, this.metrics);
|
||||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { IKibanaResponse, IRouter } from '@kbn/core/server';
|
||||
import { Metrics } from '../monitoring/metrics';
|
||||
|
||||
export const generateOtelMetrics = (router: IRouter, metrics: Metrics) => {
|
||||
router.post(
|
||||
{
|
||||
path: '/api/generate_otel_metrics',
|
||||
validate: {},
|
||||
},
|
||||
async function (_context, _req, res): Promise<IKibanaResponse<{}>> {
|
||||
metrics.requestCounter.add(1);
|
||||
return res.ok({});
|
||||
}
|
||||
);
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './generate_otel_metrics';
|
|
@ -201,6 +201,8 @@
|
|||
"@kbn/coverage-fixtures-plugin/*": ["test/common/fixtures/plugins/coverage/*"],
|
||||
"@kbn/newsfeed-fixtures-plugin": ["test/common/fixtures/plugins/newsfeed"],
|
||||
"@kbn/newsfeed-fixtures-plugin/*": ["test/common/fixtures/plugins/newsfeed/*"],
|
||||
"@kbn/open-telemetry-instrumented-plugin": ["test/common/fixtures/plugins/otel_metrics"],
|
||||
"@kbn/open-telemetry-instrumented-plugin/*": ["test/common/fixtures/plugins/otel_metrics/*"],
|
||||
"@kbn/kbn-tp-run-pipeline-plugin": ["test/interpreter_functional/plugins/kbn_tp_run_pipeline"],
|
||||
"@kbn/kbn-tp-run-pipeline-plugin/*": ["test/interpreter_functional/plugins/kbn_tp_run_pipeline/*"],
|
||||
"@kbn/app-link-test-plugin": ["test/plugin_functional/plugins/app_link_test"],
|
||||
|
|
|
@ -2,4 +2,139 @@
|
|||
|
||||
## Plugin
|
||||
|
||||
This plugin allows for other plugins to add data to Kibana stack monitoring documents.
|
||||
This plugin allows for other plugins to add data to Kibana stack monitoring documents.
|
||||
|
||||
## OpenTelemetry Metrics
|
||||
|
||||
### Enable Prometheus endpoint with Elastic Agent Prometheus input
|
||||
|
||||
1. Start [local setup with fleet](../fleet/README.md#running-fleet-server-locally-in-a-container) or a cloud cluster
|
||||
2. Start Kibana
|
||||
3. Set up a new agent policy and enroll a new agent in your local machine
|
||||
4. Install the Prometheus Metrics package
|
||||
1. Set **Hosts** with `localhost:5601`
|
||||
2. Set **Metrics Path** with `/(BASEPATH)/api/monitoring_collection/v1/prometheus`
|
||||
3. Remove the values from **Bearer Token File** and **SSL Certificate Authorities**
|
||||
4. Set **Username** and **Password** with `elastic` and `changeme`
|
||||
5. Add the following configuration to `kibana.dev.yml`
|
||||
|
||||
```yml
|
||||
# Enable the prometheus exporter
|
||||
monitoring_collection.opentelemetry.metrics:
|
||||
prometheus.enabled: true
|
||||
```
|
||||
|
||||
### Enable OpenTelemetry Metrics API exported as OpenTelemetry Protocol over GRPC
|
||||
|
||||
1. Start [local setup with fleet](../fleet/README.md#running-fleet-server-locally-in-a-container) or a cloud cluster
|
||||
2. Start Kibana
|
||||
3. Set up a new agent policy and enroll a new agent in your local machine
|
||||
4. Install Elastic APM package listening on `localhost:8200` without authentication
|
||||
5. Add the following configuration to `kibana.dev.yml`
|
||||
|
||||
```yml
|
||||
# Enable the OTLP exporter
|
||||
monitoring_collection.opentelemetry.metrics:
|
||||
otlp.url: "http://127.0.0.1:8200"
|
||||
```
|
||||
|
||||
You can also provide headers for OTLP endpoints that require authentication:
|
||||
|
||||
```yml
|
||||
# Enable the OTLP exporter to an authenticated APM endpoint
|
||||
monitoring_collection.opentelemetry.metrics:
|
||||
otlp:
|
||||
url: "https://DEPLOYMENT.apm.REGION.PROVIDER.elastic-cloud.com"
|
||||
headers:
|
||||
Authorization: "Bearer SECRET_TOKEN"
|
||||
```
|
||||
|
||||
Alternatively, OTLP Exporter can be configured using environment variables `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` and `OTEL_EXPORTER_OTLP_METRICS_HEADERS`. [See OTLP Exporter docs](https://opentelemetry.io/docs/reference/specification/protocol/exporter/) for details.
|
||||
|
||||
It's possible to configure logging for the OTLP integration. If not informed, the default will be `info`
|
||||
|
||||
```yml
|
||||
monitoring_collection.opentelemetry.metrics:
|
||||
logLevel: warn | info | debug | warn | none | verbose | all
|
||||
```
|
||||
|
||||
For connection-level debug information you can set these variables:
|
||||
|
||||
```bash
|
||||
export GRPC_NODE_TRACE="xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds"
|
||||
export GRPC_NODE_VERBOSITY=DEBUG
|
||||
```
|
||||
|
||||
See the [grpc-node docs](https://github.com/grpc/grpc-node/blob/master/doc/environment_variables.md) for details and other settings.
|
||||
|
||||
### Example of how to instrument the code
|
||||
|
||||
* First, we need to define what metrics we want to instrument with OpenTelemetry
|
||||
|
||||
```ts
|
||||
import { Counter, Meter } from '@opentelemetry/api-metrics';
|
||||
|
||||
export class FooApiMeters {
|
||||
requestCount: Counter;
|
||||
|
||||
constructor(meter: Meter) {
|
||||
this.requestCount = meter.createCounter('request_count', {
|
||||
description: 'Counts total number of requests',
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example we're using a `Counter` metric, but [OpenTelemetry SDK](https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_api_metrics.Meter.html) provides there are other options to record metrics
|
||||
|
||||
* Initialize meter in the plugin setup and pass it to the relevant components that will be instrumented. In this case, we want to instrument `FooApi` routes.
|
||||
|
||||
```ts
|
||||
import { IRouter } from '@kbn/core/server';
|
||||
import { FooApiMeters } from './foo_api_meters';
|
||||
import { metrics } from '@opentelemetry/api-metrics';
|
||||
|
||||
export class FooApiPlugin implements Plugin {
|
||||
private metrics: Metrics;
|
||||
private libs: { router: IRouter, metrics: FooApiMeters};
|
||||
|
||||
constructor() {
|
||||
this.metrics = new Metrics(metrics.getMeter('kibana.fooApi'));
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup) {
|
||||
const router = core.http.createRouter();
|
||||
|
||||
this.libs = {
|
||||
router,
|
||||
metrics: this.metrics
|
||||
}
|
||||
|
||||
initMetricsAPIRoute(this.libs);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`monitoring_collection` plugins has to be initialized before the plugin that will be instrumented. If for some reason the instrumentation doesn't record any metrics, make sure `monitoring_collection` is included in the list of `requiredPlugins`. e.g:
|
||||
|
||||
```json
|
||||
"requiredPlugins": [
|
||||
"monitoringCollection"
|
||||
],
|
||||
```
|
||||
|
||||
* Lastly we can use the `metrics` object to instrument the code
|
||||
|
||||
```ts
|
||||
export const initMetricsAPIRoute = (libs: { router: IRouter, metrics: FooApiMeters}) => {
|
||||
router.get(
|
||||
{
|
||||
path: '/api/foo',
|
||||
validate: {},
|
||||
},
|
||||
async function (_context, _req, res) {
|
||||
metrics.requestCount.add(1);
|
||||
return res.ok({});
|
||||
}
|
||||
);
|
||||
```
|
|
@ -9,6 +9,19 @@ import { schema, TypeOf } from '@kbn/config-schema';
|
|||
|
||||
export const configSchema = schema.object({
|
||||
enabled: schema.boolean({ defaultValue: true }),
|
||||
opentelemetry: schema.object({
|
||||
metrics: schema.object({
|
||||
otlp: schema.object({
|
||||
url: schema.maybe(schema.string()),
|
||||
headers: schema.maybe(schema.recordOf(schema.string(), schema.string())),
|
||||
exportIntervalMillis: schema.number({ defaultValue: 10000 }),
|
||||
logLevel: schema.string({ defaultValue: 'info' }),
|
||||
}),
|
||||
prometheus: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export type MonitoringCollectionConfig = ReturnType<typeof createConfig>;
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
* 2.0.
|
||||
*/
|
||||
export const TYPE_ALLOWLIST = ['node_rules', 'cluster_rules', 'node_actions', 'cluster_actions'];
|
||||
|
||||
export const MONITORING_COLLECTION_BASE_PATH = '/api/monitoring_collection';
|
||||
|
|
|
@ -7,3 +7,4 @@
|
|||
|
||||
export { getKibanaStats } from './get_kibana_stats';
|
||||
export { getESClusterUuid } from './get_es_cluster_uuid';
|
||||
export { PrometheusExporter } from './prometheus_exporter';
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AggregationTemporality, MetricReader } from '@opentelemetry/sdk-metrics-base';
|
||||
import {
|
||||
PrometheusExporter as OpenTelemetryPrometheusExporter,
|
||||
ExporterConfig,
|
||||
PrometheusSerializer,
|
||||
} from '@opentelemetry/exporter-prometheus';
|
||||
import { KibanaResponseFactory } from '@kbn/core/server';
|
||||
|
||||
export class PrometheusExporter extends MetricReader {
|
||||
private readonly prefix?: string;
|
||||
private readonly appendTimestamp: boolean;
|
||||
private serializer: PrometheusSerializer;
|
||||
|
||||
constructor(config: ExporterConfig = {}) {
|
||||
super();
|
||||
this.prefix = config.prefix || OpenTelemetryPrometheusExporter.DEFAULT_OPTIONS.prefix;
|
||||
this.appendTimestamp =
|
||||
typeof config.appendTimestamp === 'boolean'
|
||||
? config.appendTimestamp
|
||||
: OpenTelemetryPrometheusExporter.DEFAULT_OPTIONS.appendTimestamp;
|
||||
|
||||
this.serializer = new PrometheusSerializer(this.prefix, this.appendTimestamp);
|
||||
}
|
||||
|
||||
selectAggregationTemporality(): AggregationTemporality {
|
||||
return AggregationTemporality.CUMULATIVE;
|
||||
}
|
||||
|
||||
protected onForceFlush(): Promise<void> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
protected onShutdown(): Promise<void> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to incoming message with current state of all metrics.
|
||||
*/
|
||||
public async exportMetrics(res: KibanaResponseFactory) {
|
||||
try {
|
||||
const collectionResult = await this.collect();
|
||||
const { resourceMetrics, errors } = collectionResult;
|
||||
if (errors.length) {
|
||||
return res.customError({
|
||||
statusCode: 500,
|
||||
body: `PrometheusExporter: Metrics collection errors ${errors}`,
|
||||
});
|
||||
}
|
||||
const result = this.serializer.serialize(resourceMetrics);
|
||||
if (result === '') {
|
||||
return res.noContent();
|
||||
}
|
||||
return res.ok({
|
||||
body: result,
|
||||
});
|
||||
} catch (error) {
|
||||
return res.customError({
|
||||
statusCode: 500,
|
||||
body: {
|
||||
message: `PrometheusExporter: Failed to export metrics ${error}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,10 +6,24 @@
|
|||
*/
|
||||
|
||||
import { JsonObject } from '@kbn/utility-types';
|
||||
import { CoreSetup, Plugin, PluginInitializerContext, Logger } from '@kbn/core/server';
|
||||
import {
|
||||
CoreSetup,
|
||||
Plugin,
|
||||
PluginInitializerContext,
|
||||
Logger,
|
||||
ServiceStatus,
|
||||
} from '@kbn/core/server';
|
||||
import { MakeSchemaFrom } from '@kbn/usage-collection-plugin/server';
|
||||
import { ServiceStatus } from '@kbn/core/server';
|
||||
import { registerDynamicRoute } from './routes';
|
||||
import { metrics } from '@opentelemetry/api-metrics';
|
||||
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
|
||||
import { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics-base';
|
||||
import { Resource } from '@opentelemetry/resources';
|
||||
import { diag, DiagLogger, DiagLogLevel } from '@opentelemetry/api';
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
||||
import * as grpc from '@grpc/grpc-js';
|
||||
import { PrometheusExporter } from './lib/prometheus_exporter';
|
||||
import { MonitoringCollectionConfig } from './config';
|
||||
import { registerDynamicRoute, registerV1PrometheusRoute, PROMETHEUS_PATH } from './routes';
|
||||
import { TYPE_ALLOWLIST } from './constants';
|
||||
|
||||
export interface MonitoringCollectionSetup {
|
||||
|
@ -27,12 +41,25 @@ export interface Metric<T> {
|
|||
export class MonitoringCollectionPlugin implements Plugin<MonitoringCollectionSetup, void, {}, {}> {
|
||||
private readonly initializerContext: PluginInitializerContext;
|
||||
private readonly logger: Logger;
|
||||
private readonly config: MonitoringCollectionConfig;
|
||||
private readonly otlpLogger: DiagLogger;
|
||||
|
||||
private metrics: Record<string, Metric<any>> = {};
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext) {
|
||||
private prometheusExporter?: PrometheusExporter;
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext<MonitoringCollectionConfig>) {
|
||||
this.initializerContext = initializerContext;
|
||||
this.logger = initializerContext.logger.get();
|
||||
this.config = initializerContext.config.get();
|
||||
|
||||
this.otlpLogger = {
|
||||
debug: (message) => this.logger.debug(message),
|
||||
error: (message) => this.logger.error(message),
|
||||
info: (message) => this.logger.info(message),
|
||||
warn: (message) => this.logger.warn(message),
|
||||
verbose: (message) => this.logger.trace(message),
|
||||
};
|
||||
}
|
||||
|
||||
async getMetric(type: string) {
|
||||
|
@ -46,19 +73,28 @@ export class MonitoringCollectionPlugin implements Plugin<MonitoringCollectionSe
|
|||
setup(core: CoreSetup) {
|
||||
const router = core.http.createRouter();
|
||||
const kibanaIndex = core.savedObjects.getKibanaIndex();
|
||||
const server = core.http.getServerInfo();
|
||||
const uuid = this.initializerContext.env.instanceUuid;
|
||||
const kibanaVersion = this.initializerContext.env.packageInfo.version;
|
||||
|
||||
this.configureOpentelemetryMetrics(server.name, uuid, kibanaVersion);
|
||||
|
||||
let status: ServiceStatus<unknown>;
|
||||
core.status.overall$.subscribe((newStatus) => {
|
||||
status = newStatus;
|
||||
});
|
||||
|
||||
if (this.prometheusExporter) {
|
||||
registerV1PrometheusRoute({ router, prometheusExporter: this.prometheusExporter });
|
||||
}
|
||||
|
||||
registerDynamicRoute({
|
||||
router,
|
||||
config: {
|
||||
kibanaIndex,
|
||||
kibanaVersion: this.initializerContext.env.packageInfo.version,
|
||||
server: core.http.getServerInfo(),
|
||||
uuid: this.initializerContext.env.instanceUuid,
|
||||
kibanaVersion,
|
||||
server,
|
||||
uuid,
|
||||
},
|
||||
getStatus: () => status,
|
||||
getMetric: async (type: string) => {
|
||||
|
@ -85,6 +121,58 @@ export class MonitoringCollectionPlugin implements Plugin<MonitoringCollectionSe
|
|||
};
|
||||
}
|
||||
|
||||
private configureOpentelemetryMetrics(
|
||||
serviceName?: string,
|
||||
serviceInstanceId?: string,
|
||||
serviceVersion?: string
|
||||
) {
|
||||
const meterProvider = new MeterProvider({
|
||||
resource: new Resource({
|
||||
[SemanticResourceAttributes.SERVICE_NAME]: serviceName,
|
||||
[SemanticResourceAttributes.SERVICE_INSTANCE_ID]: serviceInstanceId,
|
||||
[SemanticResourceAttributes.SERVICE_VERSION]: serviceVersion,
|
||||
}),
|
||||
});
|
||||
|
||||
metrics.setGlobalMeterProvider(meterProvider);
|
||||
|
||||
const otlpConfig = this.config.opentelemetry?.metrics.otlp;
|
||||
const url =
|
||||
otlpConfig?.url ??
|
||||
process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ??
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
||||
if (url) {
|
||||
// Add OTLP exporter
|
||||
// Set Authorization headers
|
||||
// OTLPMetricExporter internally will look at OTEL_EXPORTER_OTLP_METRICS_HEADERS env variable
|
||||
// if `headers` is not present in the kibana config file
|
||||
const metadata = new grpc.Metadata();
|
||||
if (otlpConfig.headers) {
|
||||
for (const [key, value] of Object.entries(otlpConfig.headers)) {
|
||||
metadata.add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
const otlpLogLevel = otlpConfig.logLevel.toUpperCase() as keyof typeof DiagLogLevel;
|
||||
diag.setLogger(this.otlpLogger, DiagLogLevel[otlpLogLevel]);
|
||||
|
||||
this.logger.debug(`Registering OpenTelemetry metrics exporter to ${url}`);
|
||||
meterProvider.addMetricReader(
|
||||
new PeriodicExportingMetricReader({
|
||||
exporter: new OTLPMetricExporter({ url, metadata }),
|
||||
exportIntervalMillis: otlpConfig.exportIntervalMillis,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (this.config.opentelemetry?.metrics.prometheus.enabled) {
|
||||
// Add Prometheus exporter
|
||||
this.logger.debug(`Starting prometheus exporter at ${PROMETHEUS_PATH}`);
|
||||
this.prometheusExporter = new PrometheusExporter();
|
||||
meterProvider.addMetricReader(this.prometheusExporter);
|
||||
}
|
||||
}
|
||||
|
||||
start() {}
|
||||
|
||||
stop() {}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { registerDynamicRoute } from './dynamic_route';
|
||||
import { registerDynamicRoute } from '.';
|
||||
import { KibanaRequest, KibanaResponseFactory, ServiceStatusLevels } from '@kbn/core/server';
|
||||
import { httpServerMock, httpServiceMock } from '@kbn/core/server/mocks';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
|
@ -15,7 +15,7 @@ beforeEach(() => {
|
|||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
jest.mock('../lib', () => ({
|
||||
jest.mock('../../../../lib', () => ({
|
||||
getESClusterUuid: () => 'clusterA',
|
||||
getKibanaStats: () => ({ name: 'myKibana' }),
|
||||
}));
|
|
@ -7,8 +7,9 @@
|
|||
import { JsonObject } from '@kbn/utility-types';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter, ServiceStatus } from '@kbn/core/server';
|
||||
import { getESClusterUuid, getKibanaStats } from '../lib';
|
||||
import { MetricResult } from '../plugin';
|
||||
import { getESClusterUuid, getKibanaStats } from '../../../../lib';
|
||||
import { MetricResult } from '../../../../plugin';
|
||||
import { MONITORING_COLLECTION_BASE_PATH } from '../../../../constants';
|
||||
|
||||
export function registerDynamicRoute({
|
||||
router,
|
||||
|
@ -34,7 +35,7 @@ export function registerDynamicRoute({
|
|||
}) {
|
||||
router.get(
|
||||
{
|
||||
path: `/api/monitoring_collection/{type}`,
|
||||
path: `${MONITORING_COLLECTION_BASE_PATH}/{type}`,
|
||||
options: {
|
||||
authRequired: true,
|
||||
tags: ['api'], // ensures that unauthenticated calls receive a 401 rather than a 302 redirect to login page
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
export * from './get_metrics_by_type';
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
export { registerDynamicRoute } from './dynamic_route';
|
||||
export { registerV1PrometheusRoute, PROMETHEUS_PATH } from './prometheus';
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { RequestHandlerContext } from '@kbn/core/server';
|
||||
import { httpServerMock, httpServiceMock } from '@kbn/core/server/mocks';
|
||||
import { registerV1PrometheusRoute } from '.';
|
||||
import { PrometheusExporter } from '../../../../lib';
|
||||
|
||||
describe('Prometheus route', () => {
|
||||
it('forwards the request to the prometheus exporter', async () => {
|
||||
const router = httpServiceMock.createRouter();
|
||||
const prometheusExporter = {
|
||||
exportMetrics: jest.fn(),
|
||||
} as Partial<PrometheusExporter> as PrometheusExporter;
|
||||
|
||||
registerV1PrometheusRoute({ router, prometheusExporter });
|
||||
|
||||
const [, handler] = router.get.mock.calls[0];
|
||||
|
||||
const context = {} as jest.Mocked<RequestHandlerContext>;
|
||||
const req = httpServerMock.createKibanaRequest();
|
||||
const factory = httpServerMock.createResponseFactory();
|
||||
|
||||
await handler(context, req, factory);
|
||||
|
||||
expect(prometheusExporter.exportMetrics).toHaveBeenCalledWith(factory);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { IRouter } from '@kbn/core/server';
|
||||
import { MONITORING_COLLECTION_BASE_PATH } from '../../../../constants';
|
||||
import { PrometheusExporter } from '../../../../lib';
|
||||
|
||||
export const PROMETHEUS_PATH = `${MONITORING_COLLECTION_BASE_PATH}/v1/prometheus`;
|
||||
export function registerV1PrometheusRoute({
|
||||
router,
|
||||
prometheusExporter,
|
||||
}: {
|
||||
router: IRouter;
|
||||
prometheusExporter: PrometheusExporter;
|
||||
}) {
|
||||
router.get(
|
||||
{
|
||||
path: PROMETHEUS_PATH,
|
||||
options: {
|
||||
authRequired: true,
|
||||
tags: ['api'], // ensures that unauthenticated calls receive a 401 rather than a 302 redirect to login page
|
||||
},
|
||||
validate: {},
|
||||
},
|
||||
async (_context, _req, res) => {
|
||||
return prometheusExporter.exportMetrics(res);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
export * from './get_metrics';
|
|
@ -5,4 +5,4 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export { registerDynamicRoute } from './dynamic_route';
|
||||
export { registerV1PrometheusRoute, PROMETHEUS_PATH, registerDynamicRoute } from './api/v1';
|
||||
|
|
|
@ -36,5 +36,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./watcher'));
|
||||
loadTestFile(require.resolve('./logs_ui'));
|
||||
loadTestFile(require.resolve('./osquery'));
|
||||
loadTestFile(require.resolve('./monitoring_collection'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('Monitoring Collection', function taskManagerSuite() {
|
||||
loadTestFile(require.resolve('./prometheus'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('Prometheus endpoint', () => {
|
||||
it('returns prometheus scraped metrics', async () => {
|
||||
await supertest.post('/api/generate_otel_metrics').set('kbn-xsrf', 'foo').expect(200);
|
||||
const response = await supertest.get('/api/monitoring_collection/v1/prometheus').expect(200);
|
||||
|
||||
expect(response.text.replace(/\s+/g, ' ')).to.match(
|
||||
/^# HELP request_count_total Counts total number of requests # TYPE request_count_total counter request_count_total [0-9]/
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -37,6 +37,7 @@ export async function getApiIntegrationConfig({ readConfigFile }: FtrConfigProvi
|
|||
'--xpack.ruleRegistry.write.cache.enabled=false',
|
||||
'--xpack.uptime.service.password=test',
|
||||
'--xpack.uptime.service.username=localKibanaIntegrationTestsUser',
|
||||
'--monitoring_collection.opentelemetry.metrics.prometheus.enabled=true',
|
||||
],
|
||||
},
|
||||
esTestCluster: {
|
||||
|
|
158
yarn.lock
158
yarn.lock
|
@ -1997,6 +1997,25 @@
|
|||
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
|
||||
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
|
||||
|
||||
"@grpc/grpc-js@^1.5.9", "@grpc/grpc-js@^1.6.7":
|
||||
version "1.6.7"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.6.7.tgz#4c4fa998ff719fe859ac19fe977fdef097bb99aa"
|
||||
integrity sha512-eBM03pu9hd3VqDQG+kHahiG1x80RGkkqqRb1Pchcwqej/KkAH95gAvKs6laqaHCycYaPK+TKuNQnOz9UXYA8qw==
|
||||
dependencies:
|
||||
"@grpc/proto-loader" "^0.6.4"
|
||||
"@types/node" ">=12.12.47"
|
||||
|
||||
"@grpc/proto-loader@^0.6.4", "@grpc/proto-loader@^0.6.9":
|
||||
version "0.6.13"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.13.tgz#008f989b72a40c60c96cd4088522f09b05ac66bc"
|
||||
integrity sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==
|
||||
dependencies:
|
||||
"@types/long" "^4.0.1"
|
||||
lodash.camelcase "^4.3.0"
|
||||
long "^4.0.0"
|
||||
protobufjs "^6.11.3"
|
||||
yargs "^16.2.0"
|
||||
|
||||
"@gulp-sourcemaps/identity-map@1.X":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz#1e6fe5d8027b1f285dc0d31762f566bccd73d5a9"
|
||||
|
@ -4431,11 +4450,120 @@
|
|||
"@mattiasbuelens/web-streams-adapter" "~0.1.0"
|
||||
web-streams-polyfill "~3.0.3"
|
||||
|
||||
"@opentelemetry/api@^1.1.0":
|
||||
"@opentelemetry/api-metrics@0.30.0", "@opentelemetry/api-metrics@^0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.30.0.tgz#b5defd10756e81d1c7ce8669ff8a8d2465ba0be8"
|
||||
integrity sha512-jSb7iiYPY+DSUKIyzfGt0a5K1QGzWY5fSWtUB8Alfi27NhQGHBeuYYC5n9MaBP/HNWw5GpEIhXGEYCF9Pf8IEg==
|
||||
dependencies:
|
||||
"@opentelemetry/api" "^1.0.0"
|
||||
|
||||
"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.1.0.tgz#563539048255bbe1a5f4f586a4a10a1bb737f44a"
|
||||
integrity sha512-hf+3bwuBwtXsugA2ULBc95qxrOqP2pOekLz34BJhcAKawt94vfeNyUKpYc0lZQ/3sCP6LqRa7UAdHA7i5UODzQ==
|
||||
|
||||
"@opentelemetry/core@1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.4.0.tgz#26839ab9e36583a174273a1e1c5b33336c163725"
|
||||
integrity sha512-faq50VFEdyC7ICAOlhSi+yYZ+peznnGjTJToha9R63i9fVopzpKrkZt7AIdXUmz2+L2OqXrcJs7EIdN/oDyr5w==
|
||||
dependencies:
|
||||
"@opentelemetry/semantic-conventions" "1.4.0"
|
||||
|
||||
"@opentelemetry/exporter-metrics-otlp-grpc@^0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.30.0.tgz#4117d07b94302ef407dc7625a1b599de308c5476"
|
||||
integrity sha512-02WEAA3X7A6qveCYISr6mvg8eKl9NeNdZytQiAexzAIItW/ncN3mxmbuf8VVZHNPBe6osisSzxhPpFH3G6Gh+w==
|
||||
dependencies:
|
||||
"@grpc/grpc-js" "^1.5.9"
|
||||
"@grpc/proto-loader" "^0.6.9"
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/exporter-metrics-otlp-http" "0.30.0"
|
||||
"@opentelemetry/otlp-grpc-exporter-base" "0.30.0"
|
||||
"@opentelemetry/otlp-transformer" "0.30.0"
|
||||
"@opentelemetry/resources" "1.4.0"
|
||||
"@opentelemetry/sdk-metrics-base" "0.30.0"
|
||||
|
||||
"@opentelemetry/exporter-metrics-otlp-http@0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.30.0.tgz#9d87e4c3e796e14109ac83e6d4ce5bad215c2a1e"
|
||||
integrity sha512-2NFR/D9jih1TtEnEyD7oIMR47yb9Kuy5v2x+Fu19vv2gTf1HOhdA+LT4SpkxH+dUixEnDw8n11XBIa/uhNfq3Q==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.30.0"
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/otlp-exporter-base" "0.30.0"
|
||||
"@opentelemetry/otlp-transformer" "0.30.0"
|
||||
"@opentelemetry/resources" "1.4.0"
|
||||
"@opentelemetry/sdk-metrics-base" "0.30.0"
|
||||
|
||||
"@opentelemetry/exporter-prometheus@^0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.30.0.tgz#f81322d3cb000170e716bc76820600d5649be538"
|
||||
integrity sha512-y0SXvpzoKR+Tk/UL6F1f7vAcCzqpCDP/cTEa+Z7sX57aEG0HDXLQiLmAgK/BHqcEN5MFQMZ+MDVDsUrvpa6/Jw==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.30.0"
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/sdk-metrics-base" "0.30.0"
|
||||
|
||||
"@opentelemetry/otlp-exporter-base@0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.30.0.tgz#5f278b3529d38311dbdfc1ebcb764f5e5126e548"
|
||||
integrity sha512-+dJnj2MSd3tsk+ooEw+0bF+dJs/NjGEVnCB3/FYxnUFaW9cCBbQQyt6X3YQYtYrEx4EEiTlwrW8pUpB1tsup7A==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
|
||||
"@opentelemetry/otlp-grpc-exporter-base@0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.30.0.tgz#3fa07667ddf604a028583a2a138b8b4ba8fa9bb0"
|
||||
integrity sha512-86fuhZ7Z2un3L5Kd7jbH1oEn92v9DD92teErnYRXqYB/qyO61OLxaY6WxH9KOjmbs5CgCdLQ5bvED3wWDe3r7w==
|
||||
dependencies:
|
||||
"@grpc/grpc-js" "^1.5.9"
|
||||
"@grpc/proto-loader" "^0.6.9"
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/otlp-exporter-base" "0.30.0"
|
||||
|
||||
"@opentelemetry/otlp-transformer@0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.30.0.tgz#d81e1ae68dfb31d66cd4ca03ca965cdaa2e2b288"
|
||||
integrity sha512-BTLXyBPBlCQCG4tXYZjlso4pT+gGpnTjzkFYTPYs52fO5DMWvYHlV8ST/raOIqX7wsamiH2zeqJ9W91017MtdA==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.30.0"
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/resources" "1.4.0"
|
||||
"@opentelemetry/sdk-metrics-base" "0.30.0"
|
||||
"@opentelemetry/sdk-trace-base" "1.4.0"
|
||||
|
||||
"@opentelemetry/resources@1.4.0", "@opentelemetry/resources@^1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.4.0.tgz#5e23b0d7976158861059dec17e0ee36a35a5ab85"
|
||||
integrity sha512-Q3pI5+pCM+Ur7YwK9GbG89UBipwJbfmuzSPAXTw964ZHFzSrz+JAgrETC9rqsUOYdUlj/V7LbRMG5bo72xE0Xw==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/semantic-conventions" "1.4.0"
|
||||
|
||||
"@opentelemetry/sdk-metrics-base@0.30.0", "@opentelemetry/sdk-metrics-base@^0.30.0":
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics-base/-/sdk-metrics-base-0.30.0.tgz#242d9260a89a1ac2bf1e167b3fda758f3883c769"
|
||||
integrity sha512-3BDg1MYDInDyGvy+bSH8OuCX5nsue7omH6Y2eidCGTTDYRPxDmq9tsRJxnTUepoMAvWX+1sTwZ4JqTFmc1z8Mw==
|
||||
dependencies:
|
||||
"@opentelemetry/api-metrics" "0.30.0"
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/resources" "1.4.0"
|
||||
lodash.merge "4.6.2"
|
||||
|
||||
"@opentelemetry/sdk-trace-base@1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.4.0.tgz#e54d09c1258cd53d3fe726053ed1cbda9d74f023"
|
||||
integrity sha512-l7EEjcOgYlKWK0hfxz4Jtkkk2DuGiqBDWmRZf7g2Is9RVneF1IgcrbYZTKGaVfBKA7lPuVtUiQ2qTv3R+dKJrw==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "1.4.0"
|
||||
"@opentelemetry/resources" "1.4.0"
|
||||
"@opentelemetry/semantic-conventions" "1.4.0"
|
||||
|
||||
"@opentelemetry/semantic-conventions@1.4.0", "@opentelemetry/semantic-conventions@^1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.4.0.tgz#facf2c67d6063b9918d5a5e3fdf25f3a30d547b6"
|
||||
integrity sha512-Hzl8soGpmyzja9w3kiFFcYJ7n5HNETpplY6cb67KR4QPlxp4FTTresO06qXHgHDhyIInmbLJXuwARjjpsKYGuQ==
|
||||
|
||||
"@percy/agent@^0.28.6":
|
||||
version "0.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@percy/agent/-/agent-0.28.6.tgz#b220fab6ddcf63ae4e6c343108ba6955a772ce1c"
|
||||
|
@ -7363,6 +7491,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
|
||||
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
|
||||
|
||||
"@types/long@^4.0.1":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
||||
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
|
||||
|
||||
"@types/lru-cache@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03"
|
||||
|
@ -7530,7 +7663,7 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@12.20.24", "@types/node@16.11.41", "@types/node@>= 8", "@types/node@>=8.9.0", "@types/node@^10.1.0", "@types/node@^14.0.10", "@types/node@^14.14.31":
|
||||
"@types/node@*", "@types/node@12.20.24", "@types/node@16.11.41", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=8.9.0", "@types/node@^10.1.0", "@types/node@^14.0.10", "@types/node@^14.14.31":
|
||||
version "16.11.41"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.41.tgz#88eb485b1bfdb4c224d878b7832239536aa2f813"
|
||||
integrity sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==
|
||||
|
@ -23953,6 +24086,25 @@ protobufjs@6.8.8:
|
|||
"@types/node" "^10.1.0"
|
||||
long "^4.0.0"
|
||||
|
||||
protobufjs@^6.11.3:
|
||||
version "6.11.3"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74"
|
||||
integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
"@protobufjs/codegen" "^2.0.4"
|
||||
"@protobufjs/eventemitter" "^1.1.0"
|
||||
"@protobufjs/fetch" "^1.1.0"
|
||||
"@protobufjs/float" "^1.0.2"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
"@protobufjs/path" "^1.1.2"
|
||||
"@protobufjs/pool" "^1.1.0"
|
||||
"@protobufjs/utf8" "^1.1.0"
|
||||
"@types/long" "^4.0.1"
|
||||
"@types/node" ">=13.7.0"
|
||||
long "^4.0.0"
|
||||
|
||||
protocol-buffers-schema@^3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz#00434f608b4e8df54c59e070efeefc37fb4bb859"
|
||||
|
@ -30903,7 +31055,7 @@ yargs-unparser@2.0.0:
|
|||
flat "^5.0.2"
|
||||
is-plain-obj "^2.1.0"
|
||||
|
||||
yargs@16.2.0:
|
||||
yargs@16.2.0, yargs@^16.2.0:
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
|
||||
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue