From bf304d90a71b538b580053bce11baaa40bd38a68 Mon Sep 17 00:00:00 2001 From: Sergio Moya <1083296+smoya@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:37:12 +0100 Subject: [PATCH] chore: refactor metrics recording so it gets unified --- src/base.ts | 35 +++++++++++++++++++++++++++++- src/commands/bundle.ts | 17 ++------------- src/commands/convert.ts | 18 ++++++--------- src/commands/validate.ts | 21 ++---------------- src/hooks/prerun/invoke-metrics.ts | 11 ++++++++++ 5 files changed, 56 insertions(+), 46 deletions(-) create mode 100644 src/hooks/prerun/invoke-metrics.ts diff --git a/src/base.ts b/src/base.ts index c53ebd0270f..c137d9fec3b 100644 --- a/src/base.ts +++ b/src/base.ts @@ -1,5 +1,6 @@ import { Command } from '@oclif/core'; -import { NewRelicSink, Recorder, Sink, StdOutSink } from '@smoya/asyncapi-adoption-metrics'; +import { MetadataFromDocument, MetricMetadata, NewRelicSink, Recorder, Sink, StdOutSink } from '@smoya/asyncapi-adoption-metrics'; +import { Parser } from '@asyncapi/parser'; class DiscardSink implements Sink { async send() { @@ -9,6 +10,7 @@ class DiscardSink implements Sink { export default abstract class extends Command { recorder = recorderFromEnv('asyncapi_adoption'); + parser = new Parser(); async catch(err: Error & { exitCode?: number; }): Promise { try { @@ -20,6 +22,37 @@ export default abstract class extends Command { } } } + + async recordActionExecuted(action: string, metadata: MetricMetadata = {}, rawDocument?: string) { + if (rawDocument !== undefined) { + try { + const {document} = await this.parser.parse(rawDocument); + if (document !== undefined) { + metadata = MetadataFromDocument(document); + } + } catch (e: any) { + if (e instanceof Error) { + this.log(`Skipping submitting anonymous metrics due to the following error: ${e.name}: ${e.message}`); + } + } + } + await this.recordActionMetric(this.recorder.recordActionExecuted, action, metadata); + } + + async recordActionInvoked(action: string, metadata?: MetricMetadata) { + await this.recordActionMetric(this.recorder.recordActionInvoked, action, metadata); + } + + async recordActionMetric(recordFunc: (actionName: string, metadata?: MetricMetadata) => Promise, action: string, metadata?: MetricMetadata) { + try { + await recordFunc(action, metadata); + await this.recorder.flush(); + } catch (e: any) { + if (e instanceof Error) { + this.log(`Skipping submitting anonymous metrics due to the following error: ${e.name}: ${e.message}`); + } + } + } } function recorderFromEnv(prefix: string): Recorder { diff --git a/src/commands/bundle.ts b/src/commands/bundle.ts index 396d39a019f..d0164ac61d1 100644 --- a/src/commands/bundle.ts +++ b/src/commands/bundle.ts @@ -80,21 +80,8 @@ export default class Bundle extends Command { const result = await load(output); - try { - // Metrics recording. - const {document} = await this.parser.parse(result.text()); - if (document !== undefined) { - const metadata = MetadataFromDocument(document); - metadata['success'] = true; - metadata['files'] = AsyncAPIFiles.length; - await this.recorder.recordActionExecuted('bundle', metadata); - await this.recorder.flush(); - } - } catch (e: any) { - if (e instanceof Error) { - this.log(`Skipping submitting anonymous metrics due to the following error: ${e.name}: ${e.message}`); - } - } + // Metrics recording. + await this.recordActionExecuted(result.text(), {success: true, files: AsyncAPIFiles.length}); } async loadFiles(filepaths: string[]): Promise { diff --git a/src/commands/convert.ts b/src/commands/convert.ts index 0f93f499b5f..2b46084bc79 100644 --- a/src/commands/convert.ts +++ b/src/commands/convert.ts @@ -6,8 +6,7 @@ import { ValidationError } from '../errors/validation-error'; import { load } from '../models/SpecificationFile'; import { SpecificationFileNotFound } from '../errors/specification-file'; import { convert } from '@asyncapi/converter'; -import { MetadataFromDocument } from '@smoya/asyncapi-adoption-metrics'; -import { Parser } from '@asyncapi/parser'; +import { MetadataFromDocument, MetricMetadata } from '@smoya/asyncapi-adoption-metrics'; import type { ConvertVersion } from '@asyncapi/converter'; @@ -29,8 +28,6 @@ export default class Convert extends Command { { name: 'spec-file', description: 'spec path, url, or context-name', required: false }, ]; - parser = new Parser(); - async run() { const { args, flags } = await this.parse(Convert); const filePath = args['spec-file']; @@ -74,21 +71,20 @@ export default class Convert extends Command { } } + // Metrics recording. + let metadata: MetricMetadata = {success: true, to_version: flags['target-version']}; try { - // Metrics recording. const {document} = await this.parser.parse(specFile.text()); - if (document !== undefined && convertedFileFormatted) { - const metadata = MetadataFromDocument(document); - metadata['success'] = true; + if (document !== undefined) { + metadata = MetadataFromDocument(document, metadata); metadata['from_version'] = document.version(); - metadata['to_version'] = flags['target-version']; - await this.recorder.recordActionExecuted('convert', metadata); - await this.recorder.flush(); } } catch (e: any) { if (e instanceof Error) { this.log(`Skipping submitting anonymous metrics due to the following error: ${e.name}: ${e.message}`); } } + + await this.recordActionExecuted('convert', metadata); } } diff --git a/src/commands/validate.ts b/src/commands/validate.ts index d8f1506c85a..5757cbaffa3 100644 --- a/src/commands/validate.ts +++ b/src/commands/validate.ts @@ -5,8 +5,6 @@ import { validate, validationFlags } from '../parser'; import { load } from '../models/SpecificationFile'; import { specWatcher } from '../globals'; import { watchFlag } from '../flags'; -import { MetadataFromDocument } from '@smoya/asyncapi-adoption-metrics'; -import { Parser } from '@asyncapi/parser'; export default class Validate extends Command { static description = 'validate asyncapi file'; @@ -21,8 +19,6 @@ export default class Validate extends Command { { name: 'spec-file', description: 'spec path, url, or context-name', required: false }, ]; - parser = new Parser(); - async run() { const { args, flags } = await this.parse(Validate); //NOSONAR const filePath = args['spec-file']; @@ -35,20 +31,7 @@ export default class Validate extends Command { const result = await validate(this, specFile, flags); - try { - // Metrics recording. - const {document} = await this.parser.parse(specFile.text()); - if (document !== undefined) { - const metadata = MetadataFromDocument(document); - metadata['success'] = true; - metadata['validation_result'] = result; - await this.recorder.recordActionExecuted('validate', metadata); - await this.recorder.flush(); - } - } catch (e: any) { - if (e instanceof Error) { - this.log(`Skipping submitting anonymous metrics due to the following error: ${e.name}: ${e.message}`); - } - } + // Metrics recording. + await this.recordActionExecuted('validate', {success: true, validation_result: result}, specFile.text()); } } diff --git a/src/hooks/prerun/invoke-metrics.ts b/src/hooks/prerun/invoke-metrics.ts new file mode 100644 index 00000000000..366263990af --- /dev/null +++ b/src/hooks/prerun/invoke-metrics.ts @@ -0,0 +1,11 @@ +import {Hook} from '@oclif/core'; +// import base from '../../base'; + +const hook: Hook<'prerun'> = async function (opts) { + // opts.Command._base. + // process.stdout.write(`example hook running ${opts.Command.name.toLowerCase()}\n`); + // await (opts.Command as any as base).recorder.recordActionInvoked(opts.Command.name.toLowerCase()); + return; +}; + +export default hook;