diff --git a/docs/usage/opentelemetry.md b/docs/usage/opentelemetry.md index bfec6276211..af933805764 100644 --- a/docs/usage/opentelemetry.md +++ b/docs/usage/opentelemetry.md @@ -36,6 +36,14 @@ You can also set the following environment variables: - `OTEL_SERVICE_NAMESPACE`: to control the service namespace that will be emitted in traces, defaults to `renovatebot.com` - `OTEL_SERVICE_VERSION`: to control the service version that will be emitted in traces, defaults to using the release version of Renovate +The following resource detectors are used: + +- `EnvDetector` from @opentelemetry/resources to allow users to add the custom attributes +- `GithubDetector` from [@opentelemetry/resource-detector-github](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/detectors/node/opentelemetry-resource-detector-github) for the Github Action +- `AWSDetector` from [@opentelemetry/resource-detector-aws](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/detectors/node/opentelemetry-resource-detector-aws) Users hosting on AWS +- `GcpDetector` from [@opentelemetry/resource-detector-gcp](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/detectors/node/opentelemetry-resource-detector-gcp) Users hosting on GCP +- `AzureDetector` from [@opentelemetry/resource-detector-azure](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/detectors/node/opentelemetry-resource-detector-azure) Users hosting on Azure + ## Debugging To help you debug, you can print the telemetry to the console. diff --git a/lib/instrumentation/index.ts b/lib/instrumentation/index.ts index 3224d421120..a63fe16068f 100644 --- a/lib/instrumentation/index.ts +++ b/lib/instrumentation/index.ts @@ -14,7 +14,25 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; import { BunyanInstrumentation } from '@opentelemetry/instrumentation-bunyan'; import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; -import { resourceFromAttributes } from '@opentelemetry/resources'; +import { + awsBeanstalkDetector, + awsEc2Detector, + awsEcsDetector, + awsEksDetector, + awsLambdaDetector, +} from '@opentelemetry/resource-detector-aws'; +import { + azureAppServiceDetector, + azureFunctionsDetector, + azureVmDetector, +} from '@opentelemetry/resource-detector-azure'; +import { gcpDetector } from '@opentelemetry/resource-detector-gcp'; +import { gitHubDetector } from '@opentelemetry/resource-detector-github'; +import { + detectResources, + envDetector, + resourceFromAttributes, +} from '@opentelemetry/resources'; import { BatchSpanProcessor, ConsoleSpanExporter, @@ -55,16 +73,34 @@ export function init(): void { spanProcessors.push(new BatchSpanProcessor(exporter)); } + const baseResource = resourceFromAttributes({ + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#semantic-attributes-with-sdk-provided-default-value + [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME ?? 'renovate', + // https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv + // https://github.com/open-telemetry/opentelemetry-js/blob/e9d3c71918635d490b6a9ac9f8259265b38394d0/semantic-conventions/src/experimental_attributes.ts#L7688 + ['service.namespace']: + process.env.OTEL_SERVICE_NAMESPACE ?? 'renovatebot.com', + [ATTR_SERVICE_VERSION]: process.env.OTEL_SERVICE_VERSION ?? pkg.version, + }); + + const detectedResource = detectResources({ + detectors: [ + awsBeanstalkDetector, + awsEc2Detector, + awsEcsDetector, + awsEksDetector, + awsLambdaDetector, + azureAppServiceDetector, + azureFunctionsDetector, + azureVmDetector, + gcpDetector, + gitHubDetector, + envDetector, + ], + }); + const traceProvider = new NodeTracerProvider({ - resource: resourceFromAttributes({ - // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#semantic-attributes-with-sdk-provided-default-value - [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME ?? 'renovate', - // https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv - // https://github.com/open-telemetry/opentelemetry-js/blob/e9d3c71918635d490b6a9ac9f8259265b38394d0/semantic-conventions/src/experimental_attributes.ts#L7688 - ['service.namespace']: - process.env.OTEL_SERVICE_NAMESPACE ?? 'renovatebot.com', - [ATTR_SERVICE_VERSION]: process.env.OTEL_SERVICE_VERSION ?? pkg.version, - }), + resource: baseResource.merge(detectedResource), spanProcessors, }); diff --git a/lib/workers/repository/update/pr/body/config-description.spec.ts b/lib/workers/repository/update/pr/body/config-description.spec.ts index 25e835bde61..47a8956c831 100644 --- a/lib/workers/repository/update/pr/body/config-description.spec.ts +++ b/lib/workers/repository/update/pr/body/config-description.spec.ts @@ -53,9 +53,31 @@ describe('workers/repository/update/pr/body/config-description', () => { it('renders UTC as the default timezone', () => { const res = getPrConfigDescription({ ...config, - schedule: ['* 1 * * * *'], + schedule: ['* 1 * * *'], }); - expect(res).toContain(`"* 1 * * * *" (UTC)`); + expect(res).toContain( + 'Between 01:00 AM and 01:59 AM ( * 1 * * * ) (UTC)', + ); + }); + + it('summarizes cron schedules', () => { + const res = getPrConfigDescription({ + ...config, + schedule: ['* 1 * * *', '* * 2 * 1'], + }); + expect(res).toContain( + 'Between 01:00 AM and 01:59 AM ( * 1 * * * ), On day 2 of the month, and on Monday ( * * 2 * 1 ) (UTC)', + ); + }); + + it('displays later schedules', () => { + const res = getPrConfigDescription({ + ...config, + schedule: ['before 6am on Monday', 'after 3pm on Tuesday'], + }); + expect(res).toContain( + '"before 6am on Monday,after 3pm on Tuesday" (UTC)', + ); }); it('renders undefined schedule', () => { diff --git a/lib/workers/repository/update/pr/body/config-description.ts b/lib/workers/repository/update/pr/body/config-description.ts index 9249247ad25..4789d4a4680 100644 --- a/lib/workers/repository/update/pr/body/config-description.ts +++ b/lib/workers/repository/update/pr/body/config-description.ts @@ -1,4 +1,7 @@ +import { CronPattern } from 'croner'; +import cronstrue from 'cronstrue'; import { emojify } from '../../../../../util/emoji'; +import { capitalize } from '../../../../../util/string'; import type { BranchConfig } from '../../../../types'; export function getPrConfigDescription(config: BranchConfig): string { @@ -51,7 +54,8 @@ function scheduleToString( ): string { let scheduleString = ''; if (schedule && schedule[0] !== 'at any time') { - scheduleString += `"${String(schedule)}"`; + scheduleString = + getReadableCronSchedule(schedule) ?? `"${String(schedule)}"`; if (timezone) { scheduleString += ` in timezone ${timezone}`; } else { @@ -62,3 +66,28 @@ function scheduleToString( } return scheduleString; } + +/** + * Return human-readable cron schedule summary if the schedule is a valid cron + * else return null + */ +function getReadableCronSchedule(scheduleText: string[]): string | null { + // assuming if one schedule is cron the others in the array will be cron too + try { + new CronPattern(scheduleText[0]); // validate cron + return scheduleText + .map( + (cron) => + capitalize( + cronstrue + .toString(cron, { + throwExceptionOnParseError: false, + }) + .replace('Every minute, ', ''), + ) + ` ( ${cron} )`, + ) + .join(', '); + } catch { + return null; + } +} diff --git a/package.json b/package.json index 31ea0231f89..d818c14367a 100644 --- a/package.json +++ b/package.json @@ -161,6 +161,10 @@ "@opentelemetry/instrumentation": "0.200.0", "@opentelemetry/instrumentation-bunyan": "0.46.0", "@opentelemetry/instrumentation-http": "0.200.0", + "@opentelemetry/resource-detector-aws": "2.0.0", + "@opentelemetry/resource-detector-azure": "0.7.0", + "@opentelemetry/resource-detector-gcp": "0.34.0", + "@opentelemetry/resource-detector-github": "0.31.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "@opentelemetry/sdk-trace-node": "2.0.0", @@ -203,7 +207,7 @@ "find-packages": "10.0.4", "find-up": "5.0.0", "fs-extra": "11.3.0", - "git-url-parse": "16.0.1", + "git-url-parse": "16.1.0", "github-url-from-git": "1.5.0", "glob": "11.0.1", "global-agent": "3.0.0", @@ -285,7 +289,6 @@ "@types/diff": "7.0.2", "@types/eslint-config-prettier": "6.11.3", "@types/fs-extra": "11.0.4", - "@types/git-url-parse": "16.0.0", "@types/github-url-from-git": "1.5.3", "@types/global-agent": "3.0.0", "@types/ini": "4.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8a7c9bddc66..c15567dd21c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,6 +64,18 @@ importers: '@opentelemetry/instrumentation-http': specifier: 0.200.0 version: 0.200.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resource-detector-aws': + specifier: 2.0.0 + version: 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resource-detector-azure': + specifier: 0.7.0 + version: 0.7.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resource-detector-gcp': + specifier: 0.34.0 + version: 0.34.0(@opentelemetry/api@1.9.0)(encoding@0.1.13) + '@opentelemetry/resource-detector-github': + specifier: 0.31.0 + version: 0.31.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': specifier: 2.0.0 version: 2.0.0(@opentelemetry/api@1.9.0) @@ -191,8 +203,8 @@ importers: specifier: 11.3.0 version: 11.3.0 git-url-parse: - specifier: 16.0.1 - version: 16.0.1 + specifier: 16.1.0 + version: 16.1.0 github-url-from-git: specifier: 1.5.0 version: 1.5.0 @@ -416,9 +428,6 @@ importers: '@types/fs-extra': specifier: 11.0.4 version: 11.0.4 - '@types/git-url-parse': - specifier: 16.0.0 - version: 16.0.0 '@types/github-url-from-git': specifier: 1.5.3 version: 1.5.3 @@ -1244,7 +1253,6 @@ packages: '@ls-lint/ls-lint@2.3.0': resolution: {integrity: sha512-lsT5/7SxtImOIjpefC9wcoXt2lkikKhCjd6U+Q9Z6X5h2HBU/71ggt+XStdodZ0HkJGO333zDUeec7JROMCPFw==} - cpu: [x64, arm64, s390x, ppc64le] os: [darwin, linux, win32] hasBin: true @@ -1404,6 +1412,30 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/resource-detector-aws@2.0.0': + resolution: {integrity: sha512-jvHvLAXzFPJJhj0AdbMOpup+Fchef32sHM1Suj4NgJGKxTO47T84i5OjKiG/81YEoCaKmlTefezNbuaGCrPd3w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + + '@opentelemetry/resource-detector-azure@0.7.0': + resolution: {integrity: sha512-aR2ALsK+b/+5lLDhK9KTK8rcuKg7+sqa/Cg+QCeasqoy7qby70FRtAbQcZGljJ5BLBcVPYjl1hcTYIUyL3Laww==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + + '@opentelemetry/resource-detector-gcp@0.34.0': + resolution: {integrity: sha512-Mug9Oing1nVQE8pYT33UKuPSEa/wjQTMk3feS9F84h4U7oZIx5Mz3yddj3OHOPgrW/7d1Ve/mG7jmYqBI9tpTg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + + '@opentelemetry/resource-detector-github@0.31.0': + resolution: {integrity: sha512-m4lbj4/vZ/ylBCtID0zO4bkuN1nPoaXEPCSn7DdiPmLgcS2eE0OWPx8TGO/Rw1HceXf8/qH4KQT94bsu3usVPg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + '@opentelemetry/resources@2.0.0': resolution: {integrity: sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2126,13 +2158,6 @@ packages: '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - '@types/git-up@8.1.0': - resolution: {integrity: sha512-dKq6FQmhuWVxjvKkhGNgIx1ZthVWClz6RhgONzQXHuHFEVmDbTcy0vAIvdAEKRpBvGOPiHSxoWFKryTTLvgFvQ==} - deprecated: This is a stub types definition. git-up provides its own type definitions, so you do not need this installed. - - '@types/git-url-parse@16.0.0': - resolution: {integrity: sha512-l1xqqjwYTk0Wz8AwEezpUvns0LhTBV7RV/DOeDfIf1rbrob8Lne4ooYa2K30wJw95s1MJGXAXzx021922rUStg==} - '@types/github-url-from-git@1.5.3': resolution: {integrity: sha512-0vnjtdEpqLTRBlgkzXsRaAQ0T8Nx48fW7qWl/Y5a4MTXEL2mXFV8rNPiFPCYrJFPOeyUJRzNzcs91MgJd+fFSA==} @@ -2635,7 +2660,6 @@ packages: bignumber.js@9.2.0: resolution: {integrity: sha512-JocpCSOixzy5XFJi2ub6IMmV/G9i8Lrm2lZvwBv9xPdglmZM0ufDVBbjbrfU/zuLvBfD7Bv2eYxz9i+OHTgkew==} - deprecated: pkg version number incorrect bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} @@ -3661,8 +3685,8 @@ packages: git-up@8.1.0: resolution: {integrity: sha512-cT2f5ERrhFDMPS5wLHURcjRiacC8HonX0zIAWBTwHv1fS6HheP902l6pefOX/H9lNmvCHDwomw0VeN7nhg5bxg==} - git-url-parse@16.0.1: - resolution: {integrity: sha512-mcD36GrhAzX5JVOsIO52qNpgRyFzYWRbU1VSRFCvJt1IJvqfvH427wWw/CFqkWvjVPtdG5VTx4MKUeC5GeFPDQ==} + git-url-parse@16.1.0: + resolution: {integrity: sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==} github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -7937,6 +7961,36 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.0.0(@opentelemetry/api@1.9.0) protobufjs: 7.4.0 + '@opentelemetry/resource-detector-aws@2.0.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.30.0 + + '@opentelemetry/resource-detector-azure@0.7.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.30.0 + + '@opentelemetry/resource-detector-gcp@0.34.0(@opentelemetry/api@1.9.0)(encoding@0.1.13)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.30.0 + gcp-metadata: 6.1.1(encoding@0.1.13) + transitivePeerDependencies: + - encoding + - supports-color + + '@opentelemetry/resource-detector-github@0.31.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/resources': 2.0.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources@2.0.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8835,14 +8889,6 @@ snapshots: '@types/jsonfile': 6.1.4 '@types/node': 22.14.0 - '@types/git-up@8.1.0': - dependencies: - git-up: 8.1.0 - - '@types/git-url-parse@16.0.0': - dependencies: - '@types/git-up': 8.1.0 - '@types/github-url-from-git@1.5.3': {} '@types/global-agent@3.0.0': {} @@ -10552,7 +10598,7 @@ snapshots: is-ssh: 1.4.1 parse-url: 9.2.0 - git-url-parse@16.0.1: + git-url-parse@16.1.0: dependencies: git-up: 8.1.0