[CORL-281] Metrics (#2298)

* feat: iunitial metrics implementation

* fix: graphql endpoint was throwing errors.

* feat: add metrics env variables to readme
This commit is contained in:
Wyatt Johnson
2019-05-10 00:26:24 +02:00
committed by Kiwi
parent df57b4eb17
commit d4b8e5ef70
21 changed files with 461 additions and 92 deletions
@@ -1,9 +1,4 @@
import {
DocumentNode,
ExecutionArgs,
GraphQLError,
OperationDefinitionNode,
} from "graphql";
import { ExecutionArgs, GraphQLError } from "graphql";
import {
EndHandler,
GraphQLExtension,
@@ -12,33 +7,13 @@ import {
import now from "performance-now";
import CommonContext from "talk-server/graph/common/context";
import { getOperationMetadata } from "./helpers";
export function logError(ctx: CommonContext, err: GraphQLError) {
ctx.logger.error({ err }, "graphql query error");
}
export class LoggerExtension implements GraphQLExtension<CommonContext> {
private getOperationMetadata(doc: DocumentNode) {
if (doc.kind === "Document") {
const operationDefinition = doc.definitions.find(
({ kind }) => kind === "OperationDefinition"
) as OperationDefinitionNode | undefined;
if (operationDefinition) {
let operationName: string | undefined;
if (operationDefinition.name) {
operationName = operationDefinition.name.value;
}
return {
operationName,
operation: operationDefinition.operation,
};
}
}
return {};
}
public executionDidStart(o: {
executionArgs: ExecutionArgs;
}): EndHandler | void {
@@ -55,7 +30,7 @@ export class LoggerExtension implements GraphQLExtension<CommonContext> {
o.executionArgs.contextValue.logger.debug(
{
responseTime,
...this.getOperationMetadata(o.executionArgs.document),
...getOperationMetadata(o.executionArgs.document),
},
"graphql query"
);
@@ -0,0 +1,51 @@
import { ExecutionArgs } from "graphql";
import { EndHandler, GraphQLExtension } from "graphql-extensions";
import now from "performance-now";
import { Counter, Histogram } from "prom-client";
import CommonContext from "talk-server/graph/common/context";
import { getOperationMetadata } from "./helpers";
export interface MetricsExtensionOptions {
executedGraphQueriesTotalCounter: Counter;
graphQLExecutionTimingsHistogram: Histogram;
}
export class MetricsExtension implements GraphQLExtension<CommonContext> {
private options: MetricsExtensionOptions;
constructor(options: MetricsExtensionOptions) {
this.options = options;
}
public executionDidStart(o: {
executionArgs: ExecutionArgs;
}): EndHandler | void {
// Only try to log things if the context is provided.
if (o.executionArgs.contextValue) {
// Grab the start time so we can calculate the time it takes to execute
// the graph query.
const startTime = now();
return () => {
// Compute the end time.
const responseTime = Math.round(now() - startTime);
// Get the request metadata.
const { operation, operationName } = getOperationMetadata(
o.executionArgs.document
);
if (operation && operationName) {
// Increment the graph query value, tagging with the name of the query.
this.options.executedGraphQueriesTotalCounter
.labels(operation, operationName)
.inc();
this.options.graphQLExecutionTimingsHistogram
.labels(operation, operationName)
.observe(responseTime);
}
};
}
}
}
@@ -0,0 +1,22 @@
import { DocumentNode, OperationDefinitionNode } from "graphql";
export function getOperationMetadata(doc: DocumentNode) {
if (doc.kind === "Document") {
const operationDefinition = doc.definitions.find(
({ kind }) => kind === "OperationDefinition"
) as OperationDefinitionNode | undefined;
if (operationDefinition) {
let operationName: string | undefined;
if (operationDefinition.name) {
operationName = operationDefinition.name.value;
}
return {
operationName,
operation: operationDefinition.operation,
};
}
}
return {};
}
@@ -1,2 +1,3 @@
export * from "./ErrorWrappingExtension";
export * from "./LoggerExtension";
export * from "./MetricsExtension";