implement a helper to fetch metrics
This commit is contained in:
parent
a57f54bd58
commit
c3c12e1591
@ -1,6 +1,7 @@
|
||||
import { ServerlessCallback, ServerlessFunctionSignature } from "@twilio-labs/serverless-runtime-types/types";
|
||||
import { PrometheusContentType, Registry, Pushgateway, Summary } from "prom-client";
|
||||
import { PrometheusContentType, Registry, Pushgateway, Summary, Counter } from "prom-client";
|
||||
import { DoormanLambdaContext } from "./DoormanHandlerContext";
|
||||
import { shouldBlockRequest } from "../utils/blockUserAgent";
|
||||
|
||||
export type BaseEvent = { request: { cookies: {}; headers: {}; }; }
|
||||
|
||||
@ -13,6 +14,12 @@ export type DoormanLambda<T extends DoormanLambdaContext, U extends BaseEvent> =
|
||||
|
||||
export enum CommonMetrics {
|
||||
RUNTIME = "FunctionRuntime",
|
||||
BLOCKED_REQUEST = "BlockedRequest",
|
||||
HTTP_CLIENT_ERROR = "HttpClientError",
|
||||
};
|
||||
|
||||
export function getMetricFromRegistry<T>(metricsRegistry: Registry, metric: string): T {
|
||||
return metricsRegistry.getSingleMetric(metric) as T;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -34,7 +41,18 @@ export function withMetrics<T extends DoormanLambdaContext, U extends BaseEvent>
|
||||
help: "Runtime of the function",
|
||||
}));
|
||||
|
||||
const summaryTimer = (metricsRegistry.getSingleMetric(CommonMetrics.RUNTIME) as Summary).startTimer();
|
||||
metricsRegistry.registerMetric(new Counter({
|
||||
name: CommonMetrics.BLOCKED_REQUEST,
|
||||
help: "Blocked requests",
|
||||
}));
|
||||
|
||||
metricsRegistry.registerMetric(new Counter({
|
||||
name: CommonMetrics.HTTP_CLIENT_ERROR,
|
||||
help: "Client side HTTP error",
|
||||
labelNames: [ "ErrorCode" ],
|
||||
}));
|
||||
|
||||
const summaryTimer = getMetricFromRegistry<Summary>(metricsRegistry, CommonMetrics.RUNTIME).startTimer();
|
||||
|
||||
const startTime = Date.now();
|
||||
console.log(`[CommonHandler] started handler at ${startTime}`);
|
||||
@ -46,11 +64,28 @@ export function withMetrics<T extends DoormanLambdaContext, U extends BaseEvent>
|
||||
callbackResult = [err, payload];
|
||||
}
|
||||
|
||||
await handler(context, event, tempCallback, metricsRegistry);
|
||||
// block requests before we even call the handler
|
||||
if (shouldBlockRequest(event)) {
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, CommonMetrics.BLOCKED_REQUEST).inc(1);
|
||||
const response = new Twilio.Response();
|
||||
response.setStatusCode(200);
|
||||
callbackResult = [null, response];
|
||||
} else {
|
||||
await handler(context, event, tempCallback, metricsRegistry);
|
||||
}
|
||||
|
||||
if (!callbackResult) {
|
||||
reject("No callback was given");
|
||||
}
|
||||
|
||||
let statusCode: number | undefined = (callbackResult?.[1] as any)?.statusCode;
|
||||
|
||||
if (statusCode && statusCode >= 400) {
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, CommonMetrics.HTTP_CLIENT_ERROR).inc({
|
||||
ErrorCode: statusCode,
|
||||
}, 1);
|
||||
}
|
||||
|
||||
resolve(callbackResult as Parameters<ServerlessCallback>);
|
||||
});
|
||||
|
||||
@ -66,7 +101,7 @@ export function withMetrics<T extends DoormanLambdaContext, U extends BaseEvent>
|
||||
console.log(`[CommonHandler] there is ${remainingTime} ms left to send metrics`);
|
||||
|
||||
let metricsTimeout = setTimeout(() => {
|
||||
console.log("[CommonHandler] cutting it too close, abandoning metrics");
|
||||
console.error("[CommonHandler] cutting it too close, abandoning metrics");
|
||||
callback(...result);
|
||||
}, remainingTime - 250);
|
||||
|
||||
@ -74,6 +109,7 @@ export function withMetrics<T extends DoormanLambdaContext, U extends BaseEvent>
|
||||
|
||||
console.log("[CommonHandler] attempting to push metrics...");
|
||||
try {
|
||||
console.log(await getMetricFromRegistry<Summary>(metricsRegistry, CommonMetrics.RUNTIME).get());
|
||||
await pushGateway.push({
|
||||
jobName: functionName,
|
||||
groupings: {
|
||||
@ -82,7 +118,7 @@ export function withMetrics<T extends DoormanLambdaContext, U extends BaseEvent>
|
||||
});
|
||||
console.log("[CommonHandler] pushed metrics successfully");
|
||||
} catch (e: any) {
|
||||
console.log("[CommonHandler] failed to push metrics, quietly discarding them", e);
|
||||
console.error("[CommonHandler] failed to push metrics, quietly discarding them", e);
|
||||
}
|
||||
|
||||
clearTimeout(metricsTimeout);
|
||||
|
||||
@ -15,7 +15,7 @@ import VoiceResponse from 'twilio/lib/twiml/VoiceResponse';
|
||||
import { DoorStatus } from '../../../doorman-api/src/types/DoorStatus';
|
||||
import { StatusResponse } from '../../../doorman-api/src/functions/api/door/status';
|
||||
import { InfoResponseClient } from '../../../doorman-api/src/functions/api/door/info';
|
||||
import { withMetrics } from '../../../doorman-api/src/common/DoormanHandler';
|
||||
import { getMetricFromRegistry, withMetrics } from '../../../doorman-api/src/common/DoormanHandler';
|
||||
import { Counter, Summary } from 'prom-client';
|
||||
import { BuzzerActivatedMetrics, registerMetrics } from '../metrics/BuzzerActivatedMetrics';
|
||||
|
||||
@ -43,7 +43,9 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
||||
if (!config || !config.door) {
|
||||
let twiml = new Twilio.twiml.VoiceResponse();
|
||||
twiml.reject();
|
||||
(metricsRegistry.getSingleMetric(BuzzerActivatedMetrics.CALL_REJECTED) as Counter).inc({ From: event.From }, 1);
|
||||
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.CALL_REJECTED)
|
||||
.inc({ From: event.From }, 1);
|
||||
callback(null, twiml);
|
||||
return;
|
||||
}
|
||||
@ -62,8 +64,11 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
||||
|
||||
const unlockPromise = new Promise<VoiceResponse>((resolve, reject) => {
|
||||
intervals.push(setInterval(() => {
|
||||
(metricsRegistry.getSingleMetric(BuzzerActivatedMetrics.POLL_ATTEMPTS) as Counter).inc({ door: config.door }, 1);
|
||||
const recordPollLatency = (metricsRegistry.getSingleMetric(BuzzerActivatedMetrics.POLL_LATENCY) as Summary).startTimer({ door: config.door });
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.POLL_ATTEMPTS)
|
||||
.inc({ door: config.door }, 1);
|
||||
|
||||
const recordPollLatency = getMetricFromRegistry<Summary>(metricsRegistry, BuzzerActivatedMetrics.POLL_LATENCY)
|
||||
.startTimer({ door: config.door });
|
||||
|
||||
fetch(context.DOORMAN_URL + `/api/door/status?door=${config.door}`)
|
||||
.then(res => res.json())
|
||||
@ -79,7 +84,8 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
||||
console.log(
|
||||
invokeId, "UnlockPromise: I was the fastest, so I will attempt to notify discord users before resolving with unlock"
|
||||
);
|
||||
(metricsRegistry.getSingleMetric(BuzzerActivatedMetrics.API_UNLOCK) as Counter).inc({ door: config.door }, 1);
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.API_UNLOCK)
|
||||
.inc({ door: config.door }, 1);
|
||||
await notifyAllDiscord(context, config, `🔓 Doorman buzzed someone up @ Door "${config.door}"`, metricsRegistry, JSON.stringify(body.fingerprint));
|
||||
|
||||
resolve(twiml);
|
||||
@ -99,7 +105,8 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
||||
|
||||
if (!discordLock) {
|
||||
discordLock = true;
|
||||
(metricsRegistry.getSingleMetric(BuzzerActivatedMetrics.DIAL_THROUGH) as Counter).inc({ door: config.door }, 1);
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.DIAL_THROUGH)
|
||||
.inc({ door: config.door }, 1);
|
||||
|
||||
console.log(
|
||||
invokeId, "GracefulFallbackPromise: I was the fastest, so I will attempt to notify discord users before resolving with a call"
|
||||
@ -121,8 +128,11 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
||||
|
||||
const ungracefulFallbackPromise = new Promise<VoiceResponse>((resolve, reject) => {
|
||||
timeouts.push(setTimeout(async () => {
|
||||
(metricsRegistry.getSingleMetric(BuzzerActivatedMetrics.RESULT_NOTIFICATION_FATE_UNKNOWN) as Counter).inc({ door: config.door }, 1);
|
||||
(metricsRegistry.getSingleMetric(BuzzerActivatedMetrics.DIAL_THROUGH) as Counter).inc({ door: config.door }, 1);
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.RESULT_NOTIFICATION_FATE_UNKNOWN)
|
||||
.inc({ door: config.door }, 1);
|
||||
|
||||
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.DIAL_THROUGH)
|
||||
.inc({ door: config.door }, 1);
|
||||
|
||||
const twiml = dialFallbackTwiml(config);
|
||||
console.error(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user