forked from Azure/azure-sdk-for-js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Support for Feature & Attach Statsbeats (Azure#24470)
* Begin adding the long interval statsbeat metrics. * Modify shortHost to comply with spec. * Add callbacks for long interval statsbeats. * Update VM function to get resourceProviderId and set attach statsbeat accordingly. * Add EU endpoints to be in line with the spec. * Make the StatsbeatMonitorStatsbeatExporter public such that the AI distro can access it. * Add separate collection interval options for long and short statsbeats. * Fix test to set the correct value in the statsbeat config. * Correct statsbeat tests. * Ingest features and instrumentations from the distro and output from the appropriate exporters. * Fix feature statsbeat as a batched observable. * Add long interval immediate export. * Add to changelog. * Add long interval statsbet tests. * Document instrumentations. * Fix documentation. * Add final documentation. * Refactor long interval statsbeat. * Fix long interval tests and get rid of testing code. * Fix formatting. * Document singleton. * Clean up env variables. * Fix build issues. * Address CR comments. * Clean up comment. * Fix build process errors. * Modify project to make statsbeat details clearer and inherit shared methods.
- Loading branch information
1 parent
1706984
commit 1584998
Showing
11 changed files
with
716 additions
and
401 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
201 changes: 201 additions & 0 deletions
201
...nitor/monitor-opentelemetry-exporter/src/export/statsbeat/longIntervalStatsbeatMetrics.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT license. | ||
|
||
import { | ||
diag, | ||
BatchObservableResult, | ||
ObservableGauge, | ||
ObservableResult, | ||
Meter, | ||
} from "@opentelemetry/api"; | ||
import { ExportResult, ExportResultCode } from "@opentelemetry/core"; | ||
import { | ||
MeterProvider, | ||
PeriodicExportingMetricReader, | ||
PeriodicExportingMetricReaderOptions, | ||
} from "@opentelemetry/sdk-metrics"; | ||
import { AzureMonitorExporterOptions, AzureMonitorStatsbeatExporter } from "../../index"; | ||
import * as ai from "../../utils/constants/applicationinsights"; | ||
import { StatsbeatMetrics } from "./statsbeatMetrics"; | ||
import { | ||
StatsbeatCounter, | ||
STATSBEAT_LANGUAGE, | ||
CommonStatsbeatProperties, | ||
AttachStatsbeatProperties, | ||
StatsbeatFeatureType, | ||
StatsbeatOptions, | ||
} from "./types"; | ||
|
||
let instance: LongIntervalStatsbeatMetrics | null = null; | ||
|
||
/** | ||
* Long Interval Statsbeat Metrics | ||
* @internal | ||
*/ | ||
class LongIntervalStatsbeatMetrics extends StatsbeatMetrics { | ||
private _AZURE_MONITOR_STATSBEAT_FEATURES = process.env.AZURE_MONITOR_STATSBEAT_FEATURES; | ||
private _statsCollectionLongInterval: number = 86400000; // 1 day | ||
private _isInitialized: boolean = false; | ||
|
||
// Custom dimensions | ||
private _cikey: string; | ||
private _runtimeVersion: string; | ||
private _language: string; | ||
private _version: string; | ||
private _attach: string = "sdk"; | ||
|
||
private _commonProperties: CommonStatsbeatProperties; | ||
private _attachProperties: AttachStatsbeatProperties; | ||
|
||
private _feature: number = 0; | ||
private _instrumentation: number = 0; | ||
|
||
private _longIntervalStatsbeatMeterProvider: MeterProvider; | ||
private _longIntervalAzureExporter: AzureMonitorStatsbeatExporter; | ||
private _longIntervalMetricReader: PeriodicExportingMetricReader; | ||
private _longIntervalStatsbeatMeter: Meter; | ||
|
||
// Network Attributes | ||
private _connectionString: string; | ||
|
||
// Observable Gauges | ||
private _featureStatsbeatGauge: ObservableGauge; | ||
private _attachStatsbeatGauge: ObservableGauge; | ||
|
||
constructor(options: StatsbeatOptions) { | ||
super(); | ||
this._connectionString = super._getConnectionString(options.endpointUrl); | ||
const exporterConfig: AzureMonitorExporterOptions = { | ||
connectionString: this._connectionString, | ||
}; | ||
|
||
if (this._AZURE_MONITOR_STATSBEAT_FEATURES) { | ||
try { | ||
this._feature = JSON.parse(this._AZURE_MONITOR_STATSBEAT_FEATURES).feature; | ||
this._instrumentation = JSON.parse(this._AZURE_MONITOR_STATSBEAT_FEATURES).instrumentation; | ||
} catch (error) { | ||
diag.error( | ||
`LongIntervalStatsbeat: Failed to parse features/instrumentations (error ${error})` | ||
); | ||
} | ||
} | ||
|
||
this._longIntervalStatsbeatMeterProvider = new MeterProvider(); | ||
this._longIntervalAzureExporter = new AzureMonitorStatsbeatExporter(exporterConfig); | ||
|
||
// Export Long Interval Statsbeats every day | ||
const longIntervalMetricReaderOptions: PeriodicExportingMetricReaderOptions = { | ||
exporter: this._longIntervalAzureExporter, | ||
exportIntervalMillis: | ||
Number(process.env.LONG_INTERVAL_EXPORT_MILLIS) || this._statsCollectionLongInterval, // 1 day | ||
}; | ||
|
||
this._longIntervalMetricReader = new PeriodicExportingMetricReader( | ||
longIntervalMetricReaderOptions | ||
); | ||
this._longIntervalStatsbeatMeterProvider.addMetricReader(this._longIntervalMetricReader); | ||
this._longIntervalStatsbeatMeter = this._longIntervalStatsbeatMeterProvider.getMeter( | ||
"Azure Monitor Long Interval Statsbeat" | ||
); | ||
|
||
// Assign Common Properties | ||
this._runtimeVersion = process.version; | ||
this._language = STATSBEAT_LANGUAGE; | ||
this._version = ai.packageVersion; | ||
this._cikey = options.instrumentationKey; | ||
|
||
this._featureStatsbeatGauge = this._longIntervalStatsbeatMeter.createObservableGauge( | ||
StatsbeatCounter.FEATURE | ||
); | ||
this._attachStatsbeatGauge = this._longIntervalStatsbeatMeter.createObservableGauge( | ||
StatsbeatCounter.ATTACH | ||
); | ||
|
||
this._commonProperties = { | ||
os: super._os, | ||
rp: super._resourceProvider, | ||
cikey: this._cikey, | ||
runtimeVersion: this._runtimeVersion, | ||
language: this._language, | ||
version: this._version, | ||
attach: this._attach, | ||
}; | ||
|
||
this._attachProperties = { | ||
rpId: super._resourceIdentifier, | ||
}; | ||
|
||
this._isInitialized = true; | ||
this._initialize(); | ||
} | ||
|
||
private async _initialize() { | ||
try { | ||
await this._getResourceProvider(); | ||
|
||
// Add long interval observable callbacks | ||
this._attachStatsbeatGauge.addCallback(this._attachCallback.bind(this)); | ||
this._longIntervalStatsbeatMeter.addBatchObservableCallback( | ||
this._featureCallback.bind(this), | ||
[this._featureStatsbeatGauge] | ||
); | ||
|
||
// Export Feature/Attach Statsbeat once upon app initialization | ||
this._longIntervalAzureExporter.export( | ||
(await this._longIntervalMetricReader.collect()).resourceMetrics, | ||
(result: ExportResult) => { | ||
if (result.code !== ExportResultCode.SUCCESS) { | ||
diag.error(`LongIntervalStatsbeat: metrics export failed (error ${result.error})`); | ||
} | ||
} | ||
); | ||
} catch (error) { | ||
diag.debug("Call to get the resource provider failed."); | ||
} | ||
} | ||
|
||
private _featureCallback(observableResult: BatchObservableResult) { | ||
let attributes; | ||
if (this._instrumentation) { | ||
attributes = { | ||
...this._commonProperties, | ||
feature: this._instrumentation, | ||
type: StatsbeatFeatureType.INSTRUMENTATION, | ||
}; | ||
observableResult.observe(this._featureStatsbeatGauge, 1, { ...attributes }); | ||
} | ||
|
||
if (this._feature) { | ||
attributes = { | ||
...this._commonProperties, | ||
feature: this._feature, | ||
type: StatsbeatFeatureType.FEATURE, | ||
}; | ||
observableResult.observe(this._featureStatsbeatGauge, 1, { ...attributes }); | ||
} | ||
} | ||
|
||
private _attachCallback(observableResult: ObservableResult) { | ||
let attributes = { ...this._commonProperties, ...this._attachProperties }; | ||
observableResult.observe(1, attributes); | ||
} | ||
|
||
public isInitialized() { | ||
return this._isInitialized; | ||
} | ||
|
||
public shutdown() { | ||
this._longIntervalStatsbeatMeterProvider.shutdown(); | ||
} | ||
} | ||
|
||
/** | ||
* Singleton LongIntervalStatsbeatMetrics instance. | ||
* @internal | ||
*/ | ||
export function getInstance(options: StatsbeatOptions): LongIntervalStatsbeatMetrics { | ||
if (!instance) { | ||
instance = new LongIntervalStatsbeatMetrics(options); | ||
} | ||
return instance; | ||
} |
Oops, something went wrong.