diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index e4a23729f79..78ce09d805a 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -10,6 +10,8 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 ### :rocket: Features +* feat(config): generate types from config json schema [#6053](https://github.com/open-telemetry/opentelemetry-js/pull/6053) @JamieDanielson + ### :bug: Bug Fixes ### :books: Documentation diff --git a/experimental/packages/opentelemetry-configuration/README.md b/experimental/packages/opentelemetry-configuration/README.md index 7c4b2576bfb..c3de65d8a70 100644 --- a/experimental/packages/opentelemetry-configuration/README.md +++ b/experimental/packages/opentelemetry-configuration/README.md @@ -1,4 +1,4 @@ -# OpenTelemetry SDK for Node.js +# OpenTelemetry Configuration for Node.js [![Apache License][license-image]][license-image] @@ -20,6 +20,18 @@ To get started you need to install `@opentelemetry/configuration`. npm install @opentelemetry/configuration ``` +## Type Definitions + +This package includes TypeScript type definitions generated from the official [OpenTelemetry Configuration Schema](https://github.com/open-telemetry/opentelemetry-configuration). + +### Regenerating Types + +To regenerate the TypeScript types from the latest schema: + +```sh +npm run generate:config +``` + ## Useful links - For more information on OpenTelemetry, visit: diff --git a/experimental/packages/opentelemetry-configuration/package.json b/experimental/packages/opentelemetry-configuration/package.json index ef12c5e0060..317e26f8cd1 100644 --- a/experimental/packages/opentelemetry-configuration/package.json +++ b/experimental/packages/opentelemetry-configuration/package.json @@ -10,6 +10,7 @@ "prepublishOnly": "npm run compile", "compile": "tsc --build", "clean": "tsc --build --clean", + "generate:config": "node ../../../scripts/config/generate-config.js", "test": "nyc mocha test/**/*.test.ts", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", diff --git a/experimental/packages/opentelemetry-configuration/src/generated/opentelemetry-configuration.ts b/experimental/packages/opentelemetry-configuration/src/generated/opentelemetry-configuration.ts new file mode 100644 index 00000000000..9a64d0ee133 --- /dev/null +++ b/experimental/packages/opentelemetry-configuration/src/generated/opentelemetry-configuration.ts @@ -0,0 +1,1168 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type OtlpHttpExporter = { + /** + * Configure endpoint, including the signal specific path. + * If omitted or null, the http://localhost:4318/v1/{signal} (where signal is 'traces', 'logs', or 'metrics') is used. + */ + endpoint?: string | null; + /** Configure TLS settings for the exporter. */ + tls?: HttpTls; + /** + * Configure headers. Entries have higher priority than entries from .headers_list. + * If an entry's .value is null, the entry is ignored. + */ + headers?: NameStringValuePair[]; + /** + * Configure headers. Entries have lower priority than entries from .headers. + * The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + * If omitted or null, no headers are added. + */ + headers_list?: string | null; + /** + * Configure compression. + * Values include: gzip, none. Implementations may support other compression algorithms. + * If omitted or null, none is used. + */ + compression?: string | null; + /** + * Configure max time (in milliseconds) to wait for each export. + * Value must be non-negative. A value of 0 indicates no limit (infinity). + * If omitted or null, 10000 is used. + */ + timeout?: number | null; + /** + * Configure the encoding used for messages. + * Values include: protobuf, json. Implementations may not support json. + * If omitted or null, protobuf is used. + */ + encoding?: ('protobuf' | 'json') | null; +}; +export type HttpTls = { + /** + * Configure certificate used to verify a server's TLS credentials. + * Absolute path to certificate file in PEM format. + * If omitted or null, system default certificate verification is used for secure connections. + */ + certificate_file?: string | null; + /** + * Configure mTLS private client key. + * Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + * If omitted or null, mTLS is not used. + */ + client_key_file?: string | null; + /** + * Configure mTLS client certificate. + * Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + * If omitted or null, mTLS is not used. + */ + client_certificate_file?: string | null; +}; +export type OtlpGrpcExporter = { + /** + * Configure endpoint. + * If omitted or null, http://localhost:4317 is used. + */ + endpoint?: string | null; + /** Configure TLS settings for the exporter. */ + tls?: GrpcTls; + /** + * Configure headers. Entries have higher priority than entries from .headers_list. + * If an entry's .value is null, the entry is ignored. + */ + headers?: NameStringValuePair[]; + /** + * Configure headers. Entries have lower priority than entries from .headers. + * The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + * If omitted or null, no headers are added. + */ + headers_list?: string | null; + /** + * Configure compression. + * Values include: gzip, none. Implementations may support other compression algorithms. + * If omitted or null, none is used. + */ + compression?: string | null; + /** + * Configure max time (in milliseconds) to wait for each export. + * Value must be non-negative. A value of 0 indicates no limit (infinity). + * If omitted or null, 10000 is used. + */ + timeout?: number | null; +}; +export type GrpcTls = { + /** + * Configure certificate used to verify a server's TLS credentials. + * Absolute path to certificate file in PEM format. + * If omitted or null, system default certificate verification is used for secure connections. + */ + certificate_file?: string | null; + /** + * Configure mTLS private client key. + * Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + * If omitted or null, mTLS is not used. + */ + client_key_file?: string | null; + /** + * Configure mTLS client certificate. + * Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + * If omitted or null, mTLS is not used. + */ + client_certificate_file?: string | null; + /** + * Configure client transport security for the exporter's connection. + * Only applicable when .endpoint is provided without http or https scheme. Implementations may choose to ignore .insecure. + * If omitted or null, false is used. + */ + insecure?: boolean | null; +}; +export type ExperimentalOtlpFileExporter = { + /** + * Configure output stream. + * Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + * If omitted or null, stdout is used. + */ + output_stream?: string | null; +}; +export type ConsoleExporter = {} | null; +export type OtlpHttpMetricExporter = { + /** + * Configure endpoint. + * If omitted or null, http://localhost:4317 is used. + */ + endpoint?: string | null; + /** Configure TLS settings for the exporter. */ + tls?: HttpTls; + /** + * Configure headers. Entries have higher priority than entries from .headers_list. + * If an entry's .value is null, the entry is ignored. + */ + headers?: NameStringValuePair[]; + /** + * Configure headers. Entries have lower priority than entries from .headers. + * The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + * If omitted or null, no headers are added. + */ + headers_list?: string | null; + /** + * Configure compression. + * Values include: gzip, none. Implementations may support other compression algorithms. + * If omitted or null, none is used. + */ + compression?: string | null; + /** + * Configure max time (in milliseconds) to wait for each export. + * Value must be non-negative. A value of 0 indicates no limit (infinity). + * If omitted or null, 10000 is used. + */ + timeout?: number | null; + /** + * Configure the encoding used for messages. + * Values include: protobuf, json. Implementations may not support json. + * If omitted or null, protobuf is used. + */ + encoding?: ('protobuf' | 'json') | null; + /** + * Configure temporality preference. + * Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, cumulative is used. + */ + temporality_preference?: ('cumulative' | 'delta' | 'low_memory') | null; + /** + * Configure default histogram aggregation. + * Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, explicit_bucket_histogram is used. + */ + default_histogram_aggregation?: + | ('explicit_bucket_histogram' | 'base2_exponential_bucket_histogram') + | null; +}; +export type OtlpGrpcMetricExporter = { + /** + * Configure endpoint. + * If omitted or null, http://localhost:4317 is used. + */ + endpoint?: string | null; + /** Configure TLS settings for the exporter. */ + tls?: GrpcTls; + /** + * Configure headers. Entries have higher priority than entries from .headers_list. + * If an entry's .value is null, the entry is ignored. + */ + headers?: NameStringValuePair[]; + /** + * Configure headers. Entries have lower priority than entries from .headers. + * The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + * If omitted or null, no headers are added. + */ + headers_list?: string | null; + /** + * Configure compression. + * Values include: gzip, none. Implementations may support other compression algorithms. + * If omitted or null, none is used. + */ + compression?: string | null; + /** + * Configure max time (in milliseconds) to wait for each export. + * Value must be non-negative. A value of 0 indicates no limit (infinity). + * If omitted or null, 10000 is used. + */ + timeout?: number | null; + /** + * Configure temporality preference. + * Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, cumulative is used. + */ + temporality_preference?: ('cumulative' | 'delta' | 'low_memory') | null; + /** + * Configure default histogram aggregation. + * Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, explicit_bucket_histogram is used. + */ + default_histogram_aggregation?: + | ('explicit_bucket_histogram' | 'base2_exponential_bucket_histogram') + | null; +}; +export type ExperimentalOtlpFileMetricExporter = { + /** + * Configure output stream. + * Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + * If omitted or null, stdout is used. + */ + output_stream?: string | null; + /** + * Configure temporality preference. + * Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, cumulative is used. + */ + temporality_preference?: ('cumulative' | 'delta' | 'low_memory') | null; + /** + * Configure default histogram aggregation. + * Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, explicit_bucket_histogram is used. + */ + default_histogram_aggregation?: + | ('explicit_bucket_histogram' | 'base2_exponential_bucket_histogram') + | null; +}; +export type ConsoleMetricExporter = { + /** + * Configure temporality preference. + * Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, cumulative is used. + */ + temporality_preference?: ('cumulative' | 'delta' | 'low_memory') | null; + /** + * Configure default histogram aggregation. + * Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + * If omitted or null, explicit_bucket_histogram is used. + */ + default_histogram_aggregation?: + | ('explicit_bucket_histogram' | 'base2_exponential_bucket_histogram') + | null; +}; +export type OpenCensusMetricProducer = {} | null; +export type ExperimentalPrometheusMetricExporter = { + /** + * Configure host. + * If omitted or null, localhost is used. + */ + host?: string | null; + /** + * Configure port. + * If omitted or null, 9464 is used. + */ + port?: number | null; + /** + * Configure Prometheus Exporter to produce metrics without a scope info metric. + * If omitted or null, false is used. + */ + without_scope_info?: boolean | null; + /** Configure Prometheus Exporter to add resource attributes as metrics attributes, where the resource attribute keys match the patterns. */ + with_resource_constant_labels?: IncludeExclude; + /** + * Configure how Prometheus metrics are exposed. Values include: + * + * * UnderscoreEscapingWithSuffixes, the default. This fully escapes metric names for classic Prometheus metric name compatibility, and includes appending type and unit suffixes. + * * UnderscoreEscapingWithoutSuffixes, metric names will continue to escape special characters to _, but suffixes won't be attached. + * * NoUTF8EscapingWithSuffixes will disable changing special characters to _. Special suffixes like units and _total for counters will be attached. + * * NoTranslation. This strategy bypasses all metric and label name translation, passing them through unaltered. + * + * If omitted or null, UnderscoreEscapingWithSuffixes is used. + */ + translation_strategy?: + | ( + | 'UnderscoreEscapingWithSuffixes' + | 'UnderscoreEscapingWithoutSuffixes' + | 'NoUTF8EscapingWithSuffixes' + | 'NoTranslation' + ) + | null; +}; +export type DefaultAggregation = {} | null; +export type DropAggregation = {} | null; +export type ExplicitBucketHistogramAggregation = { + /** + * Configure bucket boundaries. + * If omitted, [0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000] is used. + */ + boundaries?: number[]; + /** + * Configure record min and max. + * If omitted or null, true is used. + */ + record_min_max?: boolean | null; +}; +export type Base2ExponentialBucketHistogramAggregation = { + /** TODO */ + max_scale?: number | null; + /** TODO */ + max_size?: number | null; + /** TODO */ + record_min_max?: boolean | null; +}; +export type LastValueAggregation = {} | null; +export type SumAggregation = {} | null; +export type TraceContextPropagator = {} | null; +export type BaggagePropagator = {} | null; +export type B3Propagator = {} | null; +export type B3MultiPropagator = {} | null; +export type JaegerPropagator = {} | null; +export type OpenTracingPropagator = {} | null; +export type ZipkinSpanExporter = { + /** + * Configure endpoint. + * If omitted or null, http://localhost:9411/api/v2/spans is used. + */ + endpoint?: string | null; + /** + * Configure max time (in milliseconds) to wait for each export. + * Value must be non-negative. A value of 0 indicates indefinite. + * If omitted or null, 10000 is used. + */ + timeout?: number | null; +}; +export type AlwaysOffSampler = {} | null; +export type AlwaysOnSampler = {} | null; +export type JaegerRemoteSampler = { + /** TODO */ + endpoint?: string | null; + /** TODO */ + interval?: number | null; + /** TODO */ + initial_sampler?: Sampler; +}; +export type ParentBasedSampler = { + /** + * Configure root sampler. + * If omitted or null, always_on is used. + */ + root?: Sampler; + /** + * Configure remote_parent_sampled sampler. + * If omitted or null, always_on is used. + */ + remote_parent_sampled?: Sampler; + /** + * Configure remote_parent_not_sampled sampler. + * If omitted or null, always_off is used. + */ + remote_parent_not_sampled?: Sampler; + /** + * Configure local_parent_sampled sampler. + * If omitted or null, always_on is used. + */ + local_parent_sampled?: Sampler; + /** + * Configure local_parent_not_sampled sampler. + * If omitted or null, always_off is used. + */ + local_parent_not_sampled?: Sampler; +}; +export type ExperimentalProbabilitySampler = { + /** + * Configure ratio. + * If omitted or null, 1.0 is used. + */ + ratio?: number | null; +}; +export type TraceIdRatioBasedSampler = { + /** + * Configure trace_id_ratio. + * If omitted or null, 1.0 is used. + */ + ratio?: number | null; +}; +export type ExperimentalContainerResourceDetector = {} | null; +export type ExperimentalHostResourceDetector = {} | null; +export type ExperimentalProcessResourceDetector = {} | null; +export type ExperimentalServiceResourceDetector = {} | null; + +export interface OpentelemetryConfiguration { + /** + * The file format version. + * The yaml format is documented at + * https://github.com/open-telemetry/opentelemetry-configuration/tree/main/schema + */ + file_format: string; + /** + * Configure if the SDK is disabled or not. + * If omitted or null, false is used. + */ + disabled?: boolean | null; + /** + * Configure the log level of the internal logger used by the SDK. + * If omitted, info is used. + */ + log_level?: string | null; + /** Configure general attribute limits. See also tracer_provider.limits, logger_provider.limits. */ + attribute_limits?: AttributeLimits; + /** + * Configure logger provider. + * If omitted, a noop logger provider is used. + */ + logger_provider?: HttpsOpentelemetryIoOtelconfigLoggerProviderJson; + /** + * Configure meter provider. + * If omitted, a noop meter provider is used. + */ + meter_provider?: HttpsOpentelemetryIoOtelconfigMeterProviderJson; + /** + * Configure text map context propagators. + * If omitted, a noop propagator is used. + */ + propagator?: HttpsOpentelemetryIoOtelconfigPropagatorJson; + /** + * Configure tracer provider. + * If omitted, a noop tracer provider is used. + */ + tracer_provider?: HttpsOpentelemetryIoOtelconfigTracerProviderJson; + /** + * Configure resource for all signals. + * If omitted, the default resource is used. + */ + resource?: HttpsOpentelemetryIoOtelconfigResourceJson; + /** Configure instrumentation. */ + 'instrumentation/development'?: HttpsOpentelemetryIoOtelconfigInstrumentationJson; + [k: string]: any | undefined; +} +export interface AttributeLimits { + /** + * Configure max attribute value size. + * Value must be non-negative. + * If omitted or null, there is no limit. + */ + attribute_value_length_limit?: number | null; + /** + * Configure max attribute count. + * Value must be non-negative. + * If omitted or null, 128 is used. + */ + attribute_count_limit?: number | null; + [k: string]: any | undefined; +} +export interface HttpsOpentelemetryIoOtelconfigLoggerProviderJson { + /** + * @minItems 1 + */ + processors: [LogRecordProcessor, ...LogRecordProcessor[]]; + /** Configure log record limits. See also attribute_limits. */ + limits?: LogRecordLimits; + /** Configure loggers. */ + 'logger_configurator/development'?: ExperimentalLoggerConfigurator; +} +export interface LogRecordProcessor { + /** Configure a batch log record processor. */ + batch?: BatchLogRecordProcessor; + /** Configure a simple log record processor. */ + simple?: SimpleLogRecordProcessor; + [k: string]: + | { + [k: string]: any | undefined; + } + | undefined; +} +export interface BatchLogRecordProcessor { + /** + * Configure delay interval (in milliseconds) between two consecutive exports. + * Value must be non-negative. + * If omitted or null, 1000 is used. + */ + schedule_delay?: number | null; + /** + * Configure maximum allowed time (in milliseconds) to export data. + * Value must be non-negative. A value of 0 indicates no limit (infinity). + * If omitted or null, 30000 is used. + */ + export_timeout?: number | null; + /** + * Configure maximum queue size. Value must be positive. + * If omitted or null, 2048 is used. + */ + max_queue_size?: number | null; + /** + * Configure maximum batch size. Value must be positive. + * If omitted or null, 512 is used. + */ + max_export_batch_size?: number | null; + /** Configure exporter. */ + exporter: LogRecordExporter; +} +export interface LogRecordExporter { + /** Configure exporter to be OTLP with HTTP transport. */ + otlp_http?: OtlpHttpExporter; + /** Configure exporter to be OTLP with gRPC transport. */ + otlp_grpc?: OtlpGrpcExporter; + /** Configure exporter to be OTLP with file transport. */ + 'otlp_file/development'?: ExperimentalOtlpFileExporter; + /** Configure exporter to be console. */ + console?: ConsoleExporter; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface NameStringValuePair { + /** The name of the pair. */ + name: string; + /** The value of the pair. */ + value: string | null; +} +export interface SimpleLogRecordProcessor { + /** Configure exporter. */ + exporter: LogRecordExporter; +} +export interface LogRecordLimits { + /** + * Configure max attribute value size. Overrides .attribute_limits.attribute_value_length_limit. + * Value must be non-negative. + * If omitted or null, there is no limit. + */ + attribute_value_length_limit?: number | null; + /** + * Configure max attribute count. Overrides .attribute_limits.attribute_count_limit. + * Value must be non-negative. + * If omitted or null, 128 is used. + */ + attribute_count_limit?: number | null; +} +export interface ExperimentalLoggerConfigurator { + /** Configure the default logger config used there is no matching entry in .logger_configurator/development.loggers. */ + default_config?: ExperimentalLoggerConfig; + /** Configure loggers. */ + loggers?: ExperimentalLoggerMatcherAndConfig[]; +} +export interface ExperimentalLoggerConfig { + /** Configure if the logger is enabled or not. */ + disabled?: boolean; +} +export interface ExperimentalLoggerMatcherAndConfig { + /** + * Configure logger names to match, evaluated as follows: + * + * * If the logger name exactly matches. + * * If the logger name matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + */ + name?: string; + /** The logger config. */ + config?: ExperimentalLoggerConfig; +} +export interface HttpsOpentelemetryIoOtelconfigMeterProviderJson { + /** + * @minItems 1 + */ + readers: [MetricReader, ...MetricReader[]]; + /** + * Configure views. + * Each view has a selector which determines the instrument(s) it applies to, and a configuration for the resulting stream(s). + */ + views?: View[]; + /** + * Configure the exemplar filter. + * Values include: trace_based, always_on, always_off. For behavior of values see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#metrics-sdk-configuration. + * If omitted or null, trace_based is used. + */ + exemplar_filter?: ('always_on' | 'always_off' | 'trace_based') | null; + /** Configure meters. */ + 'meter_configurator/development'?: ExperimentalMeterConfigurator; +} +export interface MetricReader { + /** Configure a periodic metric reader. */ + periodic?: PeriodicMetricReader; + /** Configure a pull based metric reader. */ + pull?: PullMetricReader; +} +export interface PeriodicMetricReader { + /** + * Configure delay interval (in milliseconds) between start of two consecutive exports. + * Value must be non-negative. + * If omitted or null, 60000 is used. + */ + interval?: number | null; + /** + * Configure maximum allowed time (in milliseconds) to export data. + * Value must be non-negative. A value of 0 indicates no limit (infinity). + * If omitted or null, 30000 is used. + */ + timeout?: number | null; + /** Configure exporter. */ + exporter: PushMetricExporter; + /** Configure metric producers. */ + producers?: MetricProducer[]; + /** Configure cardinality limits. */ + cardinality_limits?: CardinalityLimits; +} +export interface PushMetricExporter { + /** Configure exporter to be OTLP with HTTP transport. */ + otlp_http?: OtlpHttpMetricExporter; + /** Configure exporter to be OTLP with gRPC transport. */ + otlp_grpc?: OtlpGrpcMetricExporter; + /** Configure exporter to be OTLP with file transport. */ + 'otlp_file/development'?: ExperimentalOtlpFileMetricExporter; + /** Configure exporter to be console. */ + console?: ConsoleMetricExporter; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface MetricProducer { + /** Configure metric producer to be opencensus. */ + opencensus?: OpenCensusMetricProducer; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface CardinalityLimits { + /** + * Configure default cardinality limit for all instrument types. + * Instrument-specific cardinality limits take priority. + * If omitted or null, 2000 is used. + */ + default?: number | null; + /** + * Configure default cardinality limit for counter instruments. + * If omitted or null, the value from .default is used. + */ + counter?: number | null; + /** + * Configure default cardinality limit for gauge instruments. + * If omitted or null, the value from .default is used. + */ + gauge?: number | null; + /** + * Configure default cardinality limit for histogram instruments. + * If omitted or null, the value from .default is used. + */ + histogram?: number | null; + /** + * Configure default cardinality limit for observable_counter instruments. + * If omitted or null, the value from .default is used. + */ + observable_counter?: number | null; + /** + * Configure default cardinality limit for observable_gauge instruments. + * If omitted or null, the value from .default is used. + */ + observable_gauge?: number | null; + /** + * Configure default cardinality limit for observable_up_down_counter instruments. + * If omitted or null, the value from .default is used. + */ + observable_up_down_counter?: number | null; + /** + * Configure default cardinality limit for up_down_counter instruments. + * If omitted or null, the value from .default is used. + */ + up_down_counter?: number | null; +} +export interface PullMetricReader { + /** Configure exporter. */ + exporter: PullMetricExporter; + /** Configure metric producers. */ + producers?: MetricProducer[]; + /** Configure cardinality limits. */ + cardinality_limits?: CardinalityLimits; +} +export interface PullMetricExporter { + /** Configure exporter to be prometheus. */ + 'prometheus/development'?: ExperimentalPrometheusMetricExporter; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface IncludeExclude { + /** + * Configure list of value patterns to include. + * Values are evaluated to match as follows: + * * If the value exactly matches. + * * If the value matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + * If omitted, all values are included. + */ + included?: string[]; + /** + * Configure list of value patterns to exclude. Applies after .included (i.e. excluded has higher priority than included). + * Values are evaluated to match as follows: + * * If the value exactly matches. + * * If the value matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + * If omitted, .included attributes are included. + */ + excluded?: string[]; +} +export interface View { + /** + * Configure view selector. + * Selection criteria is additive as described in https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#instrument-selection-criteria. + */ + selector?: ViewSelector; + /** Configure view stream. */ + stream?: ViewStream; +} +export interface ViewSelector { + /** + * Configure instrument name selection criteria. + * If omitted or null, all instrument names match. + */ + instrument_name?: string | null; + /** + * Configure instrument type selection criteria. + * Values include: counter, gauge, histogram, observable_counter, observable_gauge, observable_up_down_counter, up_down_counter. + * If omitted or null, all instrument types match. + */ + instrument_type?: + | ( + | 'counter' + | 'gauge' + | 'histogram' + | 'observable_counter' + | 'observable_gauge' + | 'observable_up_down_counter' + | 'up_down_counter' + ) + | null; + /** + * Configure the instrument unit selection criteria. + * If omitted or null, all instrument units match. + */ + unit?: string | null; + /** + * Configure meter name selection criteria. + * If omitted or null, all meter names match. + */ + meter_name?: string | null; + /** + * Configure meter version selection criteria. + * If omitted or null, all meter versions match. + */ + meter_version?: string | null; + /** + * Configure meter schema url selection criteria. + * If omitted or null, all meter schema URLs match. + */ + meter_schema_url?: string | null; +} +export interface ViewStream { + /** + * Configure metric name of the resulting stream(s). + * If omitted or null, the instrument's original name is used. + */ + name?: string | null; + /** + * Configure metric description of the resulting stream(s). + * If omitted or null, the instrument's origin description is used. + */ + description?: string | null; + /** + * Configure aggregation of the resulting stream(s). + * Values include: default, drop, explicit_bucket_histogram, base2_exponential_bucket_histogram, last_value, sum. For behavior of values see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#aggregation. + * If omitted, default is used. + */ + aggregation?: Aggregation; + /** + * Configure the aggregation cardinality limit. + * If omitted or null, the metric reader's default cardinality limit is used. + */ + aggregation_cardinality_limit?: number | null; + /** Configure attribute keys retained in the resulting stream(s). */ + attribute_keys?: IncludeExclude; +} +export interface Aggregation { + /** TODO */ + default?: DefaultAggregation; + /** TODO */ + drop?: DropAggregation; + /** Configure aggregation to be explicit_bucket_histogram. */ + explicit_bucket_histogram?: ExplicitBucketHistogramAggregation; + /** TODO */ + base2_exponential_bucket_histogram?: Base2ExponentialBucketHistogramAggregation; + /** TODO */ + last_value?: LastValueAggregation; + /** TODO */ + sum?: SumAggregation; +} +export interface ExperimentalMeterConfigurator { + /** Configure the default meter config used there is no matching entry in .meter_configurator/development.meters. */ + default_config?: ExperimentalMeterConfig; + /** Configure meters. */ + meters?: ExperimentalMeterMatcherAndConfig[]; +} +export interface ExperimentalMeterConfig { + /** Configure if the meter is enabled or not. */ + disabled?: boolean; +} +export interface ExperimentalMeterMatcherAndConfig { + /** + * Configure meter names to match, evaluated as follows: + * + * * If the meter name exactly matches. + * * If the meter name matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + */ + name?: string; + /** The meter config. */ + config?: ExperimentalMeterConfig; +} +export interface HttpsOpentelemetryIoOtelconfigPropagatorJson { + /** + * Configure the propagators in the composite text map propagator. Entries from .composite_list are appended to the list here with duplicates filtered out. + * Built-in propagator keys include: tracecontext, baggage, b3, b3multi, jaeger, ottrace. Known third party keys include: xray. + * If the resolved list of propagators (from .composite and .composite_list) is empty, a noop propagator is used. + */ + composite?: TextMapPropagator[]; + /** + * Configure the propagators in the composite text map propagator. Entries are appended to .composite with duplicates filtered out. + * The value is a comma separated list of propagator identifiers matching the format of OTEL_PROPAGATORS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration for details. + * Built-in propagator identifiers include: tracecontext, baggage, b3, b3multi, jaeger, ottrace. Known third party identifiers include: xray. + * If the resolved list of propagators (from .composite and .composite_list) is empty, a noop propagator is used. + */ + composite_list?: string | null; + [k: string]: any | undefined; +} +export interface TextMapPropagator { + /** Include the w3c trace context propagator. */ + tracecontext?: TraceContextPropagator; + /** Include the w3c baggage propagator. */ + baggage?: BaggagePropagator; + /** Include the zipkin b3 propagator. */ + b3?: B3Propagator; + /** Include the zipkin b3 multi propagator. */ + b3multi?: B3MultiPropagator; + /** Include the jaeger propagator. */ + jaeger?: JaegerPropagator; + /** Include the opentracing propagator. */ + ottrace?: OpenTracingPropagator; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface HttpsOpentelemetryIoOtelconfigTracerProviderJson { + /** + * @minItems 1 + */ + processors: [SpanProcessor, ...SpanProcessor[]]; + /** Configure span limits. See also attribute_limits. */ + limits?: SpanLimits; + /** + * Configure the sampler. + * If omitted, parent based sampler with a root of always_on is used. + */ + sampler?: Sampler; + /** Configure tracers. */ + 'tracer_configurator/development'?: ExperimentalTracerConfigurator; +} +export interface SpanProcessor { + /** Configure a batch span processor. */ + batch?: BatchSpanProcessor; + /** Configure a simple span processor. */ + simple?: SimpleSpanProcessor; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface BatchSpanProcessor { + /** + * Configure delay interval (in milliseconds) between two consecutive exports. + * Value must be non-negative. + * If omitted or null, 5000 is used. + */ + schedule_delay?: number | null; + /** + * Configure maximum allowed time (in milliseconds) to export data. + * Value must be non-negative. A value of 0 indicates no limit (infinity). + * If omitted or null, 30000 is used. + */ + export_timeout?: number | null; + /** + * Configure maximum queue size. Value must be positive. + * If omitted or null, 2048 is used. + */ + max_queue_size?: number | null; + /** + * Configure maximum batch size. Value must be positive. + * If omitted or null, 512 is used. + */ + max_export_batch_size?: number | null; + /** Configure exporter. */ + exporter: SpanExporter; +} +export interface SpanExporter { + /** Configure exporter to be OTLP with HTTP transport. */ + otlp_http?: OtlpHttpExporter; + /** Configure exporter to be OTLP with gRPC transport. */ + otlp_grpc?: OtlpGrpcExporter; + /** Configure exporter to be OTLP with file transport. */ + 'otlp_file/development'?: ExperimentalOtlpFileExporter; + /** Configure exporter to be console. */ + console?: ConsoleExporter; + /** Configure exporter to be zipkin. */ + zipkin?: ZipkinSpanExporter; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface SimpleSpanProcessor { + /** Configure exporter. */ + exporter: SpanExporter; +} +export interface SpanLimits { + /** + * Configure max attribute value size. Overrides .attribute_limits.attribute_value_length_limit. + * Value must be non-negative. + * If omitted or null, there is no limit. + */ + attribute_value_length_limit?: number | null; + /** + * Configure max attribute count. Overrides .attribute_limits.attribute_count_limit. + * Value must be non-negative. + * If omitted or null, 128 is used. + */ + attribute_count_limit?: number | null; + /** + * Configure max span event count. + * Value must be non-negative. + * If omitted or null, 128 is used. + */ + event_count_limit?: number | null; + /** + * Configure max span link count. + * Value must be non-negative. + * If omitted or null, 128 is used. + */ + link_count_limit?: number | null; + /** + * Configure max attributes per span event. + * Value must be non-negative. + * If omitted or null, 128 is used. + */ + event_attribute_count_limit?: number | null; + /** + * Configure max attributes per span link. + * Value must be non-negative. + * If omitted or null, 128 is used. + */ + link_attribute_count_limit?: number | null; +} +export interface Sampler { + /** Configure sampler to be always_off. */ + always_off?: AlwaysOffSampler; + /** Configure sampler to be always_on. */ + always_on?: AlwaysOnSampler; + /** TODO */ + jaeger_remote?: JaegerRemoteSampler; + /** Configure sampler to be parent_based. */ + parent_based?: ParentBasedSampler; + /** Configure sampler to be probability. */ + 'probability/development'?: ExperimentalProbabilitySampler; + /** Configure sampler to be trace_id_ratio_based. */ + trace_id_ratio_based?: TraceIdRatioBasedSampler; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface ExperimentalTracerConfigurator { + /** Configure the default tracer config used there is no matching entry in .tracer_configurator/development.tracers. */ + default_config?: ExperimentalTracerConfig; + /** Configure tracers. */ + tracers?: ExperimentalTracerMatcherAndConfig[]; +} +export interface ExperimentalTracerConfig { + /** Configure if the tracer is enabled or not. */ + disabled?: boolean; +} +export interface ExperimentalTracerMatcherAndConfig { + /** + * Configure tracer names to match, evaluated as follows: + * + * * If the tracer name exactly matches. + * * If the tracer name matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + */ + name?: string; + /** The tracer config. */ + config?: ExperimentalTracerConfig; +} +export interface HttpsOpentelemetryIoOtelconfigResourceJson { + /** Configure resource attributes. Entries have higher priority than entries from .resource.attributes_list. */ + attributes?: AttributeNameValue[]; + /** + * Configure resource detection. + * If omitted or null, resource detection is disabled. + */ + 'detection/development'?: ExperimentalResourceDetection; + /** + * Configure resource schema URL. + * If omitted or null, no schema URL is used. + */ + schema_url?: string | null; + /** + * Configure resource attributes. Entries have lower priority than entries from .resource.attributes. + * The value is a list of comma separated key-value pairs matching the format of OTEL_RESOURCE_ATTRIBUTES. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration for details. + * If omitted or null, no resource attributes are added. + */ + attributes_list?: string | null; +} +export interface AttributeNameValue { + /** The attribute name. */ + name: string; + /** + * The attribute value. + * The type of value must match .type. + */ + value: string | number | boolean | null | string[] | boolean[] | number[]; + /** + * The attribute type. + * Values include: string, bool, int, double, string_array, bool_array, int_array, double_array. + * If omitted or null, string is used. + */ + type?: + | null + | 'string' + | 'bool' + | 'int' + | 'double' + | 'string_array' + | 'bool_array' + | 'int_array' + | 'double_array'; +} +export interface ExperimentalResourceDetection { + /** Configure attributes provided by resource detectors. */ + attributes?: IncludeExclude; + /** + * Configure resource detectors. + * Resource detector names are dependent on the SDK language ecosystem. Please consult documentation for each respective language. + * If omitted or null, no resource detectors are enabled. + */ + detectors?: ExperimentalResourceDetector[]; +} +export interface ExperimentalResourceDetector { + /** Enable the container resource detector, which populates container.* attributes. */ + container?: ExperimentalContainerResourceDetector; + /** Enable the host resource detector, which populates host.* and os.* attributes. */ + host?: ExperimentalHostResourceDetector; + /** Enable the process resource detector, which populates process.* attributes. */ + process?: ExperimentalProcessResourceDetector; + /** Enable the service detector, which populates service.name based on the OTEL_SERVICE_NAME environment variable and service.instance.id. */ + service?: ExperimentalServiceResourceDetector; + [k: string]: + | ({ + [k: string]: any | undefined; + } | null) + | undefined; +} +export interface HttpsOpentelemetryIoOtelconfigInstrumentationJson { + general?: ExperimentalGeneralInstrumentation; + cpp?: ExperimentalLanguageSpecificInstrumentation; + dotnet?: ExperimentalLanguageSpecificInstrumentation; + erlang?: ExperimentalLanguageSpecificInstrumentation; + go?: ExperimentalLanguageSpecificInstrumentation; + java?: ExperimentalLanguageSpecificInstrumentation; + js?: ExperimentalLanguageSpecificInstrumentation; + php?: ExperimentalLanguageSpecificInstrumentation; + python?: ExperimentalLanguageSpecificInstrumentation; + ruby?: ExperimentalLanguageSpecificInstrumentation; + rust?: ExperimentalLanguageSpecificInstrumentation; + swift?: ExperimentalLanguageSpecificInstrumentation; +} +export interface ExperimentalGeneralInstrumentation { + /** + * Configure instrumentations following the peer semantic conventions. + * See peer semantic conventions: https://opentelemetry.io/docs/specs/semconv/attributes-registry/peer/ + */ + peer?: ExperimentalPeerInstrumentation; + /** + * Configure instrumentations following the http semantic conventions. + * See http semantic conventions: https://opentelemetry.io/docs/specs/semconv/http/ + */ + http?: ExperimentalHttpInstrumentation; +} +export interface ExperimentalPeerInstrumentation { + /** + * Configure the service mapping for instrumentations following peer.service semantic conventions. + * See peer.service semantic conventions: https://opentelemetry.io/docs/specs/semconv/general/attributes/#general-remote-service-attributes + */ + service_mapping?: ExperimentalPeerServiceMapping[]; +} +export interface ExperimentalPeerServiceMapping { + /** The IP address to map. */ + peer: string; + /** The logical name corresponding to the IP address of .peer. */ + service: string; +} +export interface ExperimentalHttpInstrumentation { + /** Configure instrumentations following the http client semantic conventions. */ + client?: ExperimentalHttpClientInstrumentation; + /** Configure instrumentations following the http server semantic conventions. */ + server?: ExperimentalHttpServerInstrumentation; +} +export interface ExperimentalHttpClientInstrumentation { + /** Configure headers to capture for outbound http requests. */ + request_captured_headers?: string[]; + /** Configure headers to capture for inbound http responses. */ + response_captured_headers?: string[]; +} +export interface ExperimentalHttpServerInstrumentation { + /** Configure headers to capture for inbound http requests. */ + request_captured_headers?: string[]; + /** Configure headers to capture for outbound http responses. */ + response_captured_headers?: string[]; +} +export interface ExperimentalLanguageSpecificInstrumentation { + [k: string]: + | { + [k: string]: any | undefined; + } + | undefined; +} diff --git a/package-lock.json b/package-lock.json index 9450e5dee48..ad97efe4037 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "eslint-plugin-prettier": "5.5.4", "gh-pages": "6.3.0", "glob": "^11.0.0", + "json-schema-to-typescript": "^15.0.4", "karma": "6.4.4", "karma-chrome-launcher": "3.1.0", "karma-coverage": "2.2.1", @@ -1583,6 +1584,24 @@ "node": ">=6.0.0" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", + "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -4304,6 +4323,13 @@ "url": "https://opencollective.com/js-sdsl" } }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jsdoc/salty": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", @@ -7193,6 +7219,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/markdown-it": { "version": "14.1.2", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", @@ -14791,6 +14824,30 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/json-schema-to-typescript": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz", + "integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^11.5.5", + "@types/json-schema": "^7.0.15", + "@types/lodash": "^4.17.7", + "is-glob": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "prettier": "^3.2.5", + "tinyglobby": "^0.2.9" + }, + "bin": { + "json2ts": "dist/src/cli.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", diff --git a/package.json b/package.json index 6cd2f3c26b1..2eb4f038e0f 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "eslint-plugin-prettier": "5.5.4", "gh-pages": "6.3.0", "glob": "^11.0.0", + "json-schema-to-typescript": "^15.0.4", "karma": "6.4.4", "karma-chrome-launcher": "3.1.0", "karma-coverage": "2.2.1", @@ -98,9 +99,9 @@ "lerna": "9.0.0", "linkinator": "7.1.3", "markdownlint-cli2": "0.18.1", + "nx": "20.8.2", "prettier": "3.6.2", "process": "0.11.10", - "nx": "20.8.2", "semver": "7.7.3", "ts-node": "10.9.2", "typedoc": "0.27.9", diff --git a/scripts/config/generate-config.js b/scripts/config/generate-config.js new file mode 100644 index 00000000000..1df146cda3c --- /dev/null +++ b/scripts/config/generate-config.js @@ -0,0 +1,494 @@ +#!/usr/bin/env node + +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Configuration generation wrapper script + * This script: + * 1. Runs the generate_config.sh bash script to clone the schema repository + * 2. Uses json-schema-to-typescript to generate TypeScript types from the JSON schema + * 3. Post-processes the generated file by adding license headers and fixing types + */ + +const { compileFromFile } = require('json-schema-to-typescript'); +const fs = require('fs'); +const { spawnSync } = require('child_process'); +const path = require('path'); +const yaml = require('yaml'); +const ts = require('typescript'); + +const SCRIPT_DIR = __dirname; +const ROOT_DIR = path.join(SCRIPT_DIR, '..', '..'); + +// Run the bash script to get the latest version of the schema +const bashResult = spawnSync('bash', ['generate-config.sh'], { + stdio: 'inherit', + cwd: SCRIPT_DIR +}); +if (bashResult.error) { + throw bashResult.error; +} + +function addLicenseHeader(content) { + const licenseHeader = `/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +`; + + return licenseHeader + content; +} + +/** + * Manual mapping table between YAML type names and TypeScript interface/type names + * This handles cases where json-schema-to-typescript generates different names + */ +const TYPE_NAME_MAPPING = { + 'Resource': 'HttpsOpentelemetryIoOtelconfigResourceJson', + 'Propagator': 'HttpsOpentelemetryIoOtelconfigPropagatorJson', + 'LoggerProvider': 'HttpsOpentelemetryIoOtelconfigLoggerProviderJson', + 'TracerProvider': 'HttpsOpentelemetryIoOtelconfigTracerProviderJson', + 'MeterProvider': 'HttpsOpentelemetryIoOtelconfigMeterProviderJson', + 'Instrumentation': 'HttpsOpentelemetryIoOtelconfigInstrumentationJson', +}; + +/** + * Load type descriptions from YAML file + */ +function loadTypeDescriptions() { + const yamlPath = path.join(SCRIPT_DIR, 'opentelemetry-configuration/schema/meta_schema_types.yaml'); + const yamlContent = fs.readFileSync(yamlPath, 'utf8'); + const parsed = yaml.parse(yamlContent); + + // Build a map from type name to property descriptions + const typeDescriptions = new Map(); + + for (const entry of parsed) { + if (entry.type && entry.properties) { + // Convert array of {property, description} objects to a map + const propertyMap = {}; + for (const prop of entry.properties) { + if (prop.property && prop.description) { + propertyMap[prop.property] = prop.description; + } + } + typeDescriptions.set(entry.type, propertyMap); + } + } + + return typeDescriptions; +} + +/** + * Create JSDoc comment from description text + */ +function createJSDocComment(description, indent = 0) { + const indentStr = ' '.repeat(indent); + const cleanDesc = description.replace(/\n\s*\n/g, '\n\n').trim(); + const lines = cleanDesc.split('\n'); + + if (lines.length === 1) { + return `${indentStr}/** ${lines[0]} */\n`; + } + + let comment = `${indentStr}/**\n`; + for (const line of lines) { + comment += `${indentStr} * ${line}\n`; + } + comment += `${indentStr} */\n`; + + return comment; +} + +/** + * Add descriptions to generated TypeScript file + */ +function addDescriptionsToTypes(content) { + const typeDescriptions = loadTypeDescriptions(); + const sourceFile = ts.createSourceFile( + 'temp.ts', + content, + ts.ScriptTarget.Latest, + true + ); + + const modifications = []; + + function visitNode(node) { + if (ts.isInterfaceDeclaration(node) && node.name) { + const interfaceName = node.name.text; + const yamlTypes = findYamlTypesForInterface(interfaceName); + + for (const yamlType of yamlTypes) { + const descriptions = typeDescriptions.get(yamlType); + if (descriptions) { + // Add descriptions for each property + for (const member of node.members) { + if (ts.isPropertySignature(member) && member.name) { + const propertyName = getPropertyName(member.name); + const description = descriptions[propertyName]; + + if (description && !hasExistingJSDoc(member, content)) { + const indent = getIndentation(member, content); + const jsDoc = createJSDocComment(description, indent); + modifications.push({ + pos: member.pos, + jsDoc: jsDoc + }); + } + } + } + break; // Found matching type, stop searching + } + } + } + + if (ts.isTypeAliasDeclaration(node) && node.name) { + const typeName = node.name.text; + const yamlTypes = findYamlTypesForInterface(typeName); + + // For type aliases that are object types, we need to extract properties + if (node.type && ts.isTypeLiteralNode(node.type)) { + for (const yamlType of yamlTypes) { + const descriptions = typeDescriptions.get(yamlType); + if (descriptions) { + for (const member of node.type.members) { + if (ts.isPropertySignature(member) && member.name) { + const propertyName = getPropertyName(member.name); + const description = descriptions[propertyName]; + + if (description && !hasExistingJSDoc(member, content)) { + const indent = getIndentation(member, content); + const jsDoc = createJSDocComment(description, indent); + modifications.push({ + pos: member.pos, + jsDoc: jsDoc + }); + } + } + } + break; + } + } + } + + if (node.type && ts.isIntersectionTypeNode(node.type)) { + for (const typeNode of node.type.types) { + if (ts.isTypeLiteralNode(typeNode)) { + for (const yamlType of yamlTypes) { + const descriptions = typeDescriptions.get(yamlType); + if (descriptions) { + for (const member of typeNode.members) { + if (ts.isPropertySignature(member) && member.name) { + const propertyName = getPropertyName(member.name); + const description = descriptions[propertyName]; + + if (description && !hasExistingJSDoc(member, content)) { + const indent = getIndentation(member, content); + const jsDoc = createJSDocComment(description, indent); + modifications.push({ + pos: member.pos, + jsDoc: jsDoc + }); + } + } + } + break; + } + } + } + } + } + } + + ts.forEachChild(node, visitNode); + } + + visitNode(sourceFile); + + // Apply modifications in reverse order (from end to start) to maintain positions + modifications.sort((a, b) => b.pos - a.pos); + + let modifiedContent = content; + for (const mod of modifications) { + // Insert JSDoc, but remove the first newline from the content after insertion point + // to avoid double spacing (JSDoc ends with \n, and property has leading \n) + const afterContent = modifiedContent.slice(mod.pos); + const trimmedAfter = afterContent.replace(/^\n/, ''); + modifiedContent = modifiedContent.slice(0, mod.pos) + '\n' + mod.jsDoc + trimmedAfter; + } + + return modifiedContent; +} + +/** + * Find YAML type names that correspond to a TypeScript interface name + */ +function findYamlTypesForInterface(interfaceName) { + const matches = []; + + for (const [yamlType, tsNames] of Object.entries(TYPE_NAME_MAPPING)) { + if (Array.isArray(tsNames)) { + if (tsNames.includes(interfaceName)) { + matches.push(yamlType); + } + } else if (tsNames === interfaceName) { + matches.push(yamlType); + } + } + + // If no mapping found, try direct name match as fallback + if (matches.length === 0) { + matches.push(interfaceName); + } + + return matches; +} + +/** + * Get property name from PropertyName node + */ +function getPropertyName(name) { + if (ts.isIdentifier(name)) { + return name.text; + } else if (ts.isStringLiteral(name)) { + return name.text; + } + return ''; +} + +/** + * Check if a node already has JSDoc comments + */ +function hasExistingJSDoc(node, sourceText) { + const nodeStart = node.getStart(); + const textBefore = sourceText.slice(Math.max(0, node.pos), nodeStart); + return textBefore.includes('/**') || textBefore.includes('@minItems'); +} + +/** + * Get the indentation level for a node + */ +function getIndentation(node, sourceText) { + const nodeStart = node.getStart(); + const textBefore = sourceText.slice(0, nodeStart); + const lastNewline = textBefore.lastIndexOf('\n'); + + if (lastNewline === -1) { + return 0; + } + + const lineStart = lastNewline + 1; + const indent = nodeStart - lineStart; + return indent; +} + +/** + * Simplify redundant intersection types + * Converts patterns like: T & (T | null) & T & (T | null) -> T | null + */ +function simplifyRedundantIntersections(content) { + const sourceFile = ts.createSourceFile( + 'temp.ts', + content, + ts.ScriptTarget.Latest, + true + ); + + const modifications = []; + + function visitNode(node) { + // Look for type alias declarations with intersection types + if (ts.isTypeAliasDeclaration(node) && node.type && ts.isIntersectionTypeNode(node.type)) { + const intersectionTypes = node.type.types; + + // Collect type literals and check if there are nullable unions + const typeLiterals = []; + let hasNull = false; + + for (const type of intersectionTypes) { + if (ts.isTypeLiteralNode(type)) { + typeLiterals.push(type); + } else if (ts.isUnionTypeNode(type)) { + // Check if this is a union with null + for (const unionMember of type.types) { + if (unionMember.kind === ts.SyntaxKind.NullKeyword) { + hasNull = true; + } else if (ts.isTypeLiteralNode(unionMember)) { + typeLiterals.push(unionMember); + } + } + } else if (ts.isParenthesizedTypeNode(type) && ts.isUnionTypeNode(type.type)) { + // Handle parenthesized unions: (T | null) + for (const unionMember of type.type.types) { + if (unionMember.kind === ts.SyntaxKind.NullKeyword) { + hasNull = true; + } else if (ts.isTypeLiteralNode(unionMember)) { + typeLiterals.push(unionMember); + } + } + } + } + + // If we have multiple type literals that appear to be duplicates, simplify + if (typeLiterals.length > 1) { + // Check if they have the same structure (same property names) + const firstLiteral = typeLiterals[0]; + const firstProps = firstLiteral.members.map(m => + ts.isPropertySignature(m) && m.name ? getPropertyName(m.name) : '' + ).filter(Boolean).sort().join(','); + + const allSame = typeLiterals.every(literal => { + const props = literal.members.map(m => + ts.isPropertySignature(m) && m.name ? getPropertyName(m.name) : '' + ).filter(Boolean).sort().join(','); + return props === firstProps; + }); + + if (allSame) { + // Replace the entire type with simplified version + const typeStart = node.type.pos; + const typeEnd = node.type.end; + + // Extract just the first type literal text + const firstLiteralStart = firstLiteral.pos; + const firstLiteralEnd = firstLiteral.end; + let simplifiedType = content.substring(firstLiteralStart, firstLiteralEnd).trim(); + + // Add | null if any branch had it + if (hasNull) { + simplifiedType = simplifiedType + ' | null'; + } + + modifications.push({ + start: typeStart, + end: typeEnd, + replacement: ' ' + simplifiedType + }); + } + } + } + + ts.forEachChild(node, visitNode); + } + + visitNode(sourceFile); + + // Apply modifications in reverse order to maintain positions + modifications.sort((a, b) => b.start - a.start); + + let modifiedContent = content; + for (const mod of modifications) { + modifiedContent = modifiedContent.slice(0, mod.start) + mod.replacement + modifiedContent.slice(mod.end); + } + + return modifiedContent; +} + +const options = { + cwd: `${ROOT_DIR}/scripts/config/opentelemetry-configuration/schema`, + strictIndexSignatures: true, // adds undefined + unknownAny: false // too strict for simple and batch processor +} + +// compile from file +const outputPath = `${ROOT_DIR}/experimental/packages/opentelemetry-configuration/src/generated/opentelemetry-configuration.ts`; +compileFromFile(`${ROOT_DIR}/scripts/config/opentelemetry-configuration/schema/opentelemetry_configuration.json`, options) + .then(ts => { + let content = ts; + + // Simplify redundant intersection types + content = simplifyRedundantIntersections(content); + + // Fix the HttpsOpentelemetryIoOtelconfigInstrumentationJson type + // See notes below for details on why this is needed + const pattern = /(export interface HttpsOpentelemetryIoOtelconfigInstrumentationJson\s*\{[\s\S]*?)(\s+\[k: string\]: ExperimentalLanguageSpecificInstrumentation;)/; + content = content.replace(pattern, (_match, interfaceStart, _indexSignature) => { + const replacement = ` [k: string]:\n | ExperimentalLanguageSpecificInstrumentation\n | ExperimentalGeneralInstrumentation\n | undefined;`; + return interfaceStart + replacement; + }); + + // Fix the OpenTelemetryConfiguration type to be OpentelemetryConfiguration + // TODO: this is temporary, see https://github.com/open-telemetry/opentelemetry-configuration/issues/371 + const openTelemetryConfigurationPattern = "export interface OpenTelemetryConfiguration"; + content = content.replace(openTelemetryConfigurationPattern, "export interface OpentelemetryConfiguration"); + + // Add JSDoc descriptions from type_descriptions.yaml + content = addDescriptionsToTypes(content); + + // Add license header if not present + if (!content.includes('Copyright The OpenTelemetry Authors')) { + content = addLicenseHeader(content); + } + + fs.writeFileSync(outputPath, content); + + // format opentelemetry-configuration generated types + const prettierResult = spawnSync('npx', ['prettier', '--write', outputPath], { stdio: 'inherit' }); + if (prettierResult.error) { + throw prettierResult.error; + } + + // compile opentelemetry-configuration package + const compileResult = spawnSync('npm', ['run', 'compile'], { + stdio: 'inherit', + cwd: `${ROOT_DIR}/experimental/packages/opentelemetry-configuration` + }); + if (compileResult.error) { + throw compileResult.error; + } + }); + +/* notes +2 bugs in json-schema-to-typescript +Seems to miss adding | undefined to HttpsOpentelemetryIoOtelconfigInstrumentationJson +It also seems to miss the already-defined types in the generated code +https://github.com/bcherny/json-schema-to-typescript/issues/604 +https://github.com/bcherny/json-schema-to-typescript/issues/402 +related to ts issue https://github.com/microsoft/TypeScript/issues/17867 + +export interface HttpsOpentelemetryIoOtelconfigInstrumentationJson { + general?: ExperimentalGeneralInstrumentation; + cpp?: ExperimentalLanguageSpecificInstrumentation; +... + swift?: ExperimentalLanguageSpecificInstrumentation; + [k: string]: ExperimentalLanguageSpecificInstrumentation; +} + becomes + +export interface HttpsOpentelemetryIoOtelconfigInstrumentationJson { + general?: ExperimentalGeneralInstrumentation; + cpp?: ExperimentalLanguageSpecificInstrumentation; +... + swift?: ExperimentalLanguageSpecificInstrumentation; + [k: string]: + | ExperimentalLanguageSpecificInstrumentation + | ExperimentalGeneralInstrumentation + | undefined; +} +*/ diff --git a/scripts/config/generate-config.sh b/scripts/config/generate-config.sh new file mode 100755 index 00000000000..3b5f0a6cb6f --- /dev/null +++ b/scripts/config/generate-config.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -e + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="${SCRIPT_DIR}/../../" + +# Get latest version by running `git tag -l --sort=version:refname | tail -1` +# ... in git@github.com:open-telemetry/opentelemetry-configuration.git +CONFIG_VERSION=v0.4.0 + +# When running on windows and you are getting references to ";C" (like Telemetry;C) +# then this is an issue with the bash shell, so first run the following in your shell: +# export MSYS_NO_PATHCONV=1 + +cd ${SCRIPT_DIR} + +rm -rf opentelemetry-configuration || true +mkdir opentelemetry-configuration +cd opentelemetry-configuration + +git init +git remote add origin https://github.com/open-telemetry/opentelemetry-configuration.git +# git fetch origin "${CONFIG_VERSION}" --depth=1 +# TEMP: main branch has the fix that removes patternProperties from the schema +# Replace once a new tag is released +git fetch origin main +git checkout main +git reset --hard FETCH_HEAD +cd ${SCRIPT_DIR}