Skip to content

Commit b20c40e

Browse files
[SVLS-4422] Support metrics with timestamps when the Extension is running (#522)
SVLS-4422: support metrics with timestamps when the extension is running
1 parent 0b0366b commit b20c40e

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

src/metrics/listener.spec.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,51 @@ describe("MetricsListener", () => {
138138
expect(distributionMock).toHaveBeenCalledWith("my-metric", 10, undefined, ["tag:a", "tag:b"]);
139139
});
140140

141+
it("only sends metrics with timestamps to the API when the extension is enabled", async () => {
142+
const flushScope = nock(EXTENSION_URL).post("/lambda/flush", JSON.stringify({})).reply(200);
143+
mock({
144+
"/opt/extensions/datadog-agent": Buffer.from([0]),
145+
});
146+
nock("https://api.example.com").post("/api/v1/distribution_points?api_key=api-key").reply(200, {});
147+
148+
const distributionMock = jest.fn();
149+
(StatsDClient as any).mockImplementation(() => {
150+
return {
151+
distribution: distributionMock,
152+
close: (callback: any) => callback(undefined),
153+
};
154+
});
155+
156+
jest.spyOn(Date, "now").mockImplementation(() => 1487076708000);
157+
158+
const metricTimeOneMinuteAgo = new Date(Date.now() - 60000);
159+
const kms = new MockKMS("kms-api-key-decrypted");
160+
const listener = new MetricsListener(kms as any, {
161+
apiKey: "api-key",
162+
apiKeyKMS: "",
163+
enhancedMetrics: false,
164+
logForwarding: false,
165+
shouldRetryMetrics: false,
166+
localTesting: true,
167+
siteURL,
168+
});
169+
170+
await listener.onStartInvocation({});
171+
listener.sendDistributionMetricWithDate(
172+
"my-metric-with-a-timestamp",
173+
10,
174+
metricTimeOneMinuteAgo,
175+
false,
176+
"tag:a",
177+
"tag:b",
178+
);
179+
listener.sendDistributionMetric("my-metric-without-a-timestamp", 10, false, "tag:a", "tag:b");
180+
await listener.onCompleteInvocation();
181+
expect(flushScope.isDone()).toBeTruthy();
182+
expect(nock.isDone()).toBeTruthy();
183+
expect(distributionMock).toHaveBeenCalledWith("my-metric-without-a-timestamp", 10, undefined, ["tag:a", "tag:b"]);
184+
});
185+
141186
it("logs metrics when logForwarding is enabled with custom timestamp", async () => {
142187
const spy = jest.spyOn(process.stdout, "write");
143188
// jest.spyOn(Date, "now").mockImplementation(() => 1487076708000);

src/metrics/listener.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,20 @@ export class MetricsListener {
131131
public sendDistributionMetricWithDate(
132132
name: string,
133133
value: number,
134-
metricTime: Date,
134+
metricTime: Date, // TODO: Next breaking change to update to optional or 'Date | undefined'?
135135
forceAsync: boolean,
136136
...tags: string[]
137137
) {
138138
if (this.isExtensionRunning) {
139-
this.statsDClient?.distribution(name, value, undefined, tags);
140-
return;
139+
const isMetricTimeValid = Date.parse(metricTime.toString()) > 0;
140+
if (isMetricTimeValid) {
141+
// Only create the processor to submit metrics to the API when a user provides a valid timestamp as
142+
// Dogstatsd does not support timestamps for distributions.
143+
this.currentProcessor = this.createProcessor(this.config, this.apiKey);
144+
} else {
145+
this.statsDClient?.distribution(name, value, undefined, tags);
146+
return;
147+
}
141148
}
142149
if (this.config.logForwarding || forceAsync) {
143150
writeMetricToStdout(name, value, metricTime, tags);
@@ -162,11 +169,13 @@ export class MetricsListener {
162169
}
163170

164171
public sendDistributionMetric(name: string, value: number, forceAsync: boolean, ...tags: string[]) {
165-
this.sendDistributionMetricWithDate(name, value, new Date(Date.now()), forceAsync, ...tags);
172+
// The Extension doesn't support distribution metrics with timestamps. Use sendDistributionMetricWithDate instead.
173+
const metricTime = this.isExtensionRunning ? new Date(0) : new Date(Date.now());
174+
this.sendDistributionMetricWithDate(name, value, metricTime, forceAsync, ...tags);
166175
}
167176

168177
private async createProcessor(config: MetricsConfig, apiKey: Promise<string>) {
169-
if (!this.isExtensionRunning && !this.config.logForwarding) {
178+
if (!this.config.logForwarding) {
170179
const { APIClient } = require("./api");
171180
const { Processor } = require("./processor");
172181

0 commit comments

Comments
 (0)