Skip to content

Commit

Permalink
chore: refactoring host metrics, aligning with semantic conventions (#…
Browse files Browse the repository at this point in the history
…266)

* chore: refactoring host metrics, aligning with semantic conventions

* chore: updating host metrics to v0.13 of core and simplifying data collection due to latest changes

* chore: lint

* chore: fixing tests

* chore: fixing descriptions
  • Loading branch information
obecny authored Dec 11, 2020
1 parent 4ed223b commit f039f1f
Show file tree
Hide file tree
Showing 17 changed files with 504 additions and 362 deletions.
30 changes: 21 additions & 9 deletions examples/host-metrics/node.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
'use strict';

const { HostMetrics } = require('@opentelemetry/host-metrics');
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
// const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
const { MeterProvider } = require('@opentelemetry/metrics');
const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');
const exporter = new CollectorMetricExporter({
headers: {},
serviceName: 'test-host-metrics',
// url: '',
});

const exporter = new PrometheusExporter(
{
startServer: true,
},
() => {
console.log('prometheus scrape endpoint: http://localhost:9464/metrics');
},
);
// for testing purposes if you don't want to use CollectorMetricExporter
// const exporter = new PrometheusExporter(
// {
// startServer: true,
// },
// () => {
// console.log('prometheus scrape endpoint: http://localhost:9464/metrics');
// },
// );

const meterProvider = new MeterProvider({
exporter,
Expand All @@ -20,3 +27,8 @@ const meterProvider = new MeterProvider({

const hostMetrics = new HostMetrics({ meterProvider, name: 'example-host-metrics' });
hostMetrics.start();

// keep running
(function wait () {
setTimeout(wait, 1000);
})();
9 changes: 5 additions & 4 deletions examples/host-metrics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
"url": "https://github.com/open-telemetry/opentelemetry-js/issues"
},
"dependencies": {
"@opentelemetry/api": "^0.12.0",
"@opentelemetry/core": "^0.12.0",
"@opentelemetry/exporter-prometheus": "^0.12.0",
"@opentelemetry/metrics": "^0.12.0",
"@opentelemetry/api": "^0.13.0",
"@opentelemetry/core": "^0.13.0",
"@opentelemetry/exporter-prometheus": "^0.13.0",
"@opentelemetry/exporter-collector": "^0.13.0",
"@opentelemetry/metrics": "^0.13.0",
"@opentelemetry/host-metrics": "^0.11.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js#readme"
Expand Down
8 changes: 4 additions & 4 deletions packages/opentelemetry-host-metrics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@
"typescript": "3.9.7"
},
"dependencies": {
"@opentelemetry/api": "^0.12.0",
"@opentelemetry/core": "^0.12.0",
"@opentelemetry/metrics": "^0.12.0",
"systeminformation": "^4.27.10"
"@opentelemetry/api": "^0.13.0",
"@opentelemetry/core": "^0.13.0",
"@opentelemetry/metrics": "^0.13.0",
"systeminformation": "^4.31.0"
}
}
125 changes: 125 additions & 0 deletions packages/opentelemetry-host-metrics/src/BaseMetrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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.
*/

import * as api from '@opentelemetry/api';
import * as metrics from '@opentelemetry/metrics';

import { VERSION } from './version';

/**
* Metrics Collector Configuration
*/
export interface MetricsCollectorConfig {
logger?: api.Logger;
// maximum timeout to wait for stats collection default is 500ms
maxTimeoutUpdateMS?: number;
// Meter Provider
meterProvider?: metrics.MeterProvider;
// Character to be used to join metrics - default is "."
metricNameSeparator?: string;
// Name of component
name: string;
// metric export endpoint
url?: string;
}

const DEFAULT_MAX_TIMEOUT_UPDATE_MS = 500;
const DEFAULT_NAME = 'opentelemetry-host-metrics';
const DEFAULT_METRIC_NAME_SEPARATOR = '.';

// default label name to be used to store metric name
const DEFAULT_KEY = 'name';

/**
* Base Class for metrics
*/
export abstract class BaseMetrics {
protected _logger: api.Logger | undefined;
protected _maxTimeoutUpdateMS: number;
protected _meter: metrics.Meter;
private _name: string;
private _boundCounters: { [key: string]: api.BoundCounter } = {};
private _metricNameSeparator: string;

constructor(config: MetricsCollectorConfig) {
this._logger = config.logger || new api.NoopLogger();
this._name = config.name || DEFAULT_NAME;
this._maxTimeoutUpdateMS =
config.maxTimeoutUpdateMS || DEFAULT_MAX_TIMEOUT_UPDATE_MS;
this._metricNameSeparator =
config.metricNameSeparator || DEFAULT_METRIC_NAME_SEPARATOR;
const meterProvider =
config.meterProvider! || api.metrics.getMeterProvider();
if (!config.meterProvider) {
this._logger.warn('No meter provider, using default');
}
this._meter = meterProvider.getMeter(this._name, VERSION);
}

/**
* Creates a metric key name based on metric name and a key
* @param metricName
* @param key
*/
protected _boundKey(metricName: string, key: string) {
if (!key) {
return metricName;
}
return `${metricName}${this._metricNameSeparator}${key}`;
}

/**
* Updates counter based on boundkey
* @param metricName
* @param key
* @param value
*/
protected _counterUpdate(metricName: string, key: string, value = 0) {
const boundKey = this._boundKey(metricName, key);
this._boundCounters[boundKey].add(value);
}

/**
* @param metricName metric name - this will be added as label under name
* "name"
* @param values values to be used to generate bound counters for each
* value prefixed with metricName
* @param description metric description
*/
protected _createCounter(
metricName: string,
values: string[],
description?: string
) {
const keys = values.map(key => this._boundKey(metricName, key));
const counter = this._meter.createCounter(metricName, {
description: description || metricName,
});
keys.forEach(key => {
this._boundCounters[key] = counter.bind({ [DEFAULT_KEY]: key });
});
}

/**
* Creates metrics
*/
protected abstract _createMetrics(): void;

/**
* Starts collecting stats
*/
public abstract start(): void;
}
24 changes: 14 additions & 10 deletions packages/opentelemetry-host-metrics/src/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,28 @@
*/

export enum METRIC_NAMES {
CPU = 'cpu',
NETWORK = 'net',
MEMORY = 'mem',
CPU_TIME = 'system.cpu.time',
CPU_UTILIZATION = 'system.cpu.utilization',
MEMORY_USAGE = 'system.memory.usage',
MEMORY_UTILIZATION = 'system.memory.utilization',
NETWORK_DROPPED = 'system.network.dropped',
NETWORK_ERRORS = 'system.network.errors',
NETWORK_IO = 'system.network.io',
}

export enum CPU_LABELS {
USER = 'user',
SYSTEM = 'sys',
USAGE = 'usage',
TOTAL = 'total',
SYSTEM = 'system',
IDLE = 'idle',
}

export enum NETWORK_LABELS {
BYTES_SENT = 'bytesSent',
BYTES_RECEIVED = 'bytesRecv',
DEVICE = 'device',
RECEIVE = 'receive',
TRANSMIT = 'transmit',
}

export enum MEMORY_LABELS {
AVAILABLE = 'available',
TOTAL = 'total',
FREE = 'free',
USED = 'used',
}
1 change: 1 addition & 0 deletions packages/opentelemetry-host-metrics/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
* limitations under the License.
*/

export * from './BaseMetrics';
export * from './metric';
export * from './types';
Loading

0 comments on commit f039f1f

Please sign in to comment.