Skip to content

Commit

Permalink
Update @instrumented decorator and other type tweaks (#3)
Browse files Browse the repository at this point in the history
* Tweak `instrumented` to take in meter name

* Type rename, export plus tsdoc updates

* Support passing of attributes for `instrument`
  • Loading branch information
niwsa authored Apr 11, 2023
1 parent 764ddd5 commit 4efba72
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 48 deletions.
11 changes: 8 additions & 3 deletions src/instruments/counter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import { acquireMeter } from "../lib/meter";

const counters: Record<string, Counter<Attributes>> = {};

type OperationParams = {
type CounterOperationParams = {
/** OTel meter name */
meter: string;
/** Metric name being instrumented */
name: string;
/** Value by which counter is incremented, defaults to 1 */
inc?: number;
/** MetricOptions such as unit */
counterOptions?: MetricOptions;
/** Metric Attributes in the form of key value pairs */
counterAttributes?: Attributes;
};

Expand All @@ -17,7 +22,7 @@ const incrementCounter = ({
inc = 1,
counterOptions,
counterAttributes,
}: OperationParams) => {
}: CounterOperationParams) => {
let counter = counters[name];
if (counter === undefined) {
const _otelMeter = acquireMeter(meter);
Expand All @@ -26,4 +31,4 @@ const incrementCounter = ({
counter.add(inc, counterAttributes);
};

export { incrementCounter };
export { incrementCounter, type CounterOperationParams };
11 changes: 8 additions & 3 deletions src/instruments/gauge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ import { acquireMeter } from "../lib/meter";

const gauges: Record<string, ObservableGauge<Attributes>> = {};

type OperationParams = {
type GaugeOperationParams = {
/** OTel meter name */
meter: string;
/** Metric name being instrumented */
name: string;
/** Non-additive value observed at a point in time */
val: number;
/** MetricOptions such as unit */
gaugeOptions?: MetricOptions;
/** Metric Attributes in the form of key value pairs */
gaugeAttributes?: Attributes;
};

Expand All @@ -21,7 +26,7 @@ const observeGauge = ({
val,
gaugeOptions,
gaugeAttributes,
}: OperationParams) => {
}: GaugeOperationParams) => {
let gauge = gauges[name];
if (gauge === undefined) {
const _otelMeter = acquireMeter(meter);
Expand All @@ -32,4 +37,4 @@ const observeGauge = ({
});
};

export { observeGauge };
export { observeGauge, type GaugeOperationParams };
11 changes: 8 additions & 3 deletions src/instruments/histogram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import { acquireMeter } from "../lib/meter";

const histograms: Record<string, Histogram<Attributes>> = {};

type OperationParams = {
type HistogramOperationParams = {
/** OTel meter name */
meter: string;
/** Metric name being instrumented */
name: string;
/** Value to be recorded */
val: number;
/** MetricOptions such as unit */
histogramOptions?: MetricOptions;
/** Metric Attributes in the form of key value pairs */
histogramAttributes?: Attributes;
};

Expand All @@ -17,7 +22,7 @@ const recordHistogram = ({
val,
histogramOptions,
histogramAttributes,
}: OperationParams) => {
}: HistogramOperationParams) => {
let histogram = histograms[name];
if (histogram === undefined) {
const _otelMeter = acquireMeter(meter);
Expand All @@ -29,4 +34,4 @@ const recordHistogram = ({
histogram.record(val, histogramAttributes);
};

export { recordHistogram };
export { recordHistogram, type HistogramOperationParams };
10 changes: 5 additions & 5 deletions src/instruments/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { incrementCounter } from "./counter";
export { observeGauge } from "./gauge";
export { recordHistogram } from "./histogram";
export { recordTimer } from "./timer";
export { instrument, instrumented } from "./instrument";
export * from "./counter";
export * from "./gauge";
export * from "./histogram";
export * from "./timer";
export * from "./instrument";
69 changes: 38 additions & 31 deletions src/instruments/instrument.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import type { Attributes } from "@opentelemetry/api";
import { incrementCounter } from "./counter";
import { recordTimer } from "./timer";

type InstrumentParams = {
type InstrumentOperationParams = {
/** OTel meter name */
meter: string;
/** Function name being instrumented */
name: string;
/** Handle to execute the function */
delegate: () => unknown;
/** Metric Attributes in the form of key value pairs */
instrumentAttributes?: Attributes;
};

/**
Expand All @@ -16,15 +19,20 @@ type InstrumentParams = {
* @param operationParams
*/

async function instrument({ meter, name, delegate }: InstrumentParams) {
async function instrument({
meter,
name,
delegate,
instrumentAttributes,
}: InstrumentOperationParams) {
const start = process.hrtime();
try {
return await delegate();
} catch (err) {
incrementCounter({
meter,
name: "function.errors",
counterAttributes: { function: name },
counterAttributes: { function: name, ...instrumentAttributes },
});
throw err;
} finally {
Expand All @@ -34,44 +42,43 @@ async function instrument({ meter, name, delegate }: InstrumentParams) {
meter,
name: "function.executionTime",
val: elapsedNanos,
timerAttributes: { function: name },
timerAttributes: { function: name, ...instrumentAttributes },
});
}
}

/**
* Decorator that instruments a class method
*
* @param meter - Name of OTel meter
*/
function instrumented(
meter: string,
target: any,
key: string,
descriptor?: PropertyDescriptor
) {
if (descriptor === undefined) {
descriptor = Object.getOwnPropertyDescriptor(target, key);
}
if (descriptor === undefined) {
return descriptor;
}
function instrumented(meter: string) {
return function (target: any, key: string, descriptor?: PropertyDescriptor) {
if (descriptor === undefined) {
descriptor = Object.getOwnPropertyDescriptor(target, key);
}
if (descriptor === undefined) {
return descriptor;
}

const originalMethod = descriptor.value;
const klass = target.constructor.name;
const originalMethod = descriptor.value;
const klass = target.constructor.name;

// this needs to be a non-arrow function or we'll get the wrong `this`
function overrideMethod(this: unknown, ...args: any[]) {
return instrument({
meter,
name: `${klass}.${key}`,
delegate: async () => {
return await originalMethod.apply(this, args);
},
});
}
// this needs to be a non-arrow function or we'll get the wrong `this`
function overrideMethod(this: unknown, ...args: any[]) {
return instrument({
meter,
name: `${klass}.${key}`,
delegate: async () => {
return await originalMethod.apply(this, args);
},
});
}

descriptor.value = overrideMethod;
descriptor.value = overrideMethod;

return descriptor;
return descriptor;
};
}

export { instrument, instrumented };
export { instrument, instrumented, type InstrumentOperationParams };
11 changes: 8 additions & 3 deletions src/instruments/timer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import { acquireMeter } from "../lib/meter";

const timers: Record<string, Histogram<Attributes>> = {};

type OperationParams = {
type TimerOperationParams = {
/** OTel meter name */
meter: string;
/** Metric name being instrumented */
name: string;
/** Timer value to be recorded */
val: number;
/** MetricOptions such as unit */
timerOptions?: MetricOptions;
/** Metric Attributes in the form of key value pairs */
timerAttributes?: Attributes;
};

Expand All @@ -17,7 +22,7 @@ const recordTimer = ({
val,
timerOptions,
timerAttributes,
}: OperationParams) => {
}: TimerOperationParams) => {
let timer = timers[name];
if (timer === undefined) {
const _otelMeter = acquireMeter(meter);
Expand All @@ -29,4 +34,4 @@ const recordTimer = ({
timer.record(val, timerAttributes);
};

export { recordTimer };
export { recordTimer, type TimerOperationParams };

0 comments on commit 4efba72

Please sign in to comment.