Skip to content

Commit

Permalink
add nice grpc metrice handler
Browse files Browse the repository at this point in the history
  • Loading branch information
iQQBot authored and roboquat committed Sep 27, 2022
1 parent 481267b commit c4c6554
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 6 deletions.
10 changes: 6 additions & 4 deletions components/gitpod-protocol/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@
"src"
],
"devDependencies": {
"@grpc/grpc-js": "^1.3.7",
"@types/analytics-node": "^3.1.9",
"@types/chai-subset": "^1.3.3",
"@types/cookie": "^0.4.1",
"@types/express": "^4.17.13",
"@grpc/grpc-js": "^1.3.7",
"@types/google-protobuf": "^3.15.5",
"@types/jaeger-client": "^3.18.3",
"@types/js-yaml": "^3.10.1",
"@types/mocha": "^5.2.7",
"@types/node": "^16.11.6",
"@types/random-number-csprng": "^1.0.0",
"@types/uuid": "^8.3.1",
"@types/ws": "^5.1.2",
"@types/google-protobuf": "^3.15.5",
"chai": "^4.3.4",
"chai-subset": "^1.6.0",
"mocha": "^5.0.0",
Expand All @@ -42,14 +42,17 @@
},
"dependencies": {
"@types/react": "17.0.32",
"abort-controller-x": "^0.4.0",
"ajv": "^6.5.4",
"analytics-node": "^6.0.0",
"configcat-node": "^8.0.0",
"cookie": "^0.4.2",
"express": "^4.17.3",
"google-protobuf": "^3.19.1",
"inversify": "^5.1.1",
"jaeger-client": "^3.18.1",
"js-yaml": "^3.10.0",
"nice-grpc-common": "^2.0.0",
"opentracing": "^0.14.5",
"prom-client": "^13.2.0",
"random-number-csprng": "^1.0.2",
Expand All @@ -63,7 +66,6 @@
"vscode-languageserver-types": "3.17.0",
"vscode-uri": "^3.0.3",
"vscode-ws-jsonrpc": "^0.2.0",
"ws": "^7.4.6",
"google-protobuf": "^3.19.1"
"ws": "^7.4.6"
}
}
93 changes: 93 additions & 0 deletions components/gitpod-protocol/src/util/nice-grpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License-AGPL.txt in the project root for license information.
*/

import { isAbortError } from "abort-controller-x";
import {
CallOptions,
ClientError,
ClientMiddleware,
ClientMiddlewareCall,
Status,
MethodDescriptor,
} from "nice-grpc-common";
import { GrpcMethodType, IClientCallMetrics } from "./grpc";

function getLabels(method: MethodDescriptor) {
const callType = method.requestStream
? method.responseStream
? "bidi_stream"
: "client_stream"
: method.responseStream
? "server_stream"
: "unary";
const { path } = method;
const [serviceName, methodName] = path.split("/").slice(1);

return {
type: callType as GrpcMethodType,
service: serviceName,
method: methodName,
};
}

async function* incrementStreamMessagesCounter<T>(iterable: AsyncIterable<T>, callback: () => void): AsyncIterable<T> {
for await (const item of iterable) {
callback();
yield item;
}
}

export function prometheusClientMiddleware(metrics: IClientCallMetrics): ClientMiddleware {
return async function* prometheusClientMiddlewareGenerator<Request, Response>(
call: ClientMiddlewareCall<Request, Response>,
options: CallOptions,
): AsyncGenerator<Response, Response | void, undefined> {
const labels = getLabels(call.method);

metrics.started(labels);

let settled = false;
let status: Status = Status.OK;

try {
let request;

if (!call.requestStream) {
request = call.request;
} else {
request = incrementStreamMessagesCounter(call.request, metrics.sent.bind(metrics, labels));
}

if (!call.responseStream) {
const response = yield* call.next(request, options);
settled = true;
return response;
} else {
yield* incrementStreamMessagesCounter(
call.next(request, options),
metrics.received.bind(metrics, labels),
);
settled = true;
return;
}
} catch (err) {
settled = true;
if (err instanceof ClientError) {
status = err.code;
} else if (isAbortError(err)) {
status = Status.CANCELLED;
} else {
status = Status.UNKNOWN;
}
throw err;
} finally {
if (!settled) {
status = Status.CANCELLED;
}
metrics.handled({ ...labels, code: Status[status] });
}
};
}
8 changes: 6 additions & 2 deletions components/server/src/container-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ import { LicenseEvaluator } from "@gitpod/licensor/lib";
import { WorkspaceClusterImagebuilderClientProvider } from "./workspace/workspace-cluster-imagebuilder-client-provider";
import { UsageServiceClient, UsageServiceDefinition } from "@gitpod/usage-api/lib/usage/v1/usage.pb";
import { BillingServiceClient, BillingServiceDefinition } from "@gitpod/usage-api/lib/usage/v1/billing.pb";
import { createChannel, createClient } from "nice-grpc";
import { createChannel, createClient, createClientFactory } from "nice-grpc";
import { CommunityEntitlementService, EntitlementService } from "./billing/entitlement-service";
import {
ConfigCatClientFactory,
Expand All @@ -111,6 +111,7 @@ import { VerificationService } from "./auth/verification-service";
import { WebhookEventGarbageCollector } from "./projects/webhook-event-garbage-collector";
import { LivenessController } from "./liveness/liveness-controller";
import { IDEServiceClient, IDEServiceDefinition } from "@gitpod/ide-service-api/lib/ide.pb";
import { prometheusClientMiddleware } from "@gitpod/gitpod-protocol/lib/util/nice-grpc";

export const productionContainerModule = new ContainerModule((bind, unbind, isBound, rebind) => {
bind(Config).toConstantValue(ConfigFile.fromFile());
Expand Down Expand Up @@ -271,7 +272,10 @@ export const productionContainerModule = new ContainerModule((bind, unbind, isBo

bind<IDEServiceClient>(IDEServiceDefinition.name).toDynamicValue((ctx) => {
const config = ctx.container.get<Config>(Config);
return createClient(IDEServiceDefinition, createChannel(config.ideServiceAddr));
const metricsClient = ctx.container.get<IClientCallMetrics>(IClientCallMetrics);
return createClientFactory()
.use(prometheusClientMiddleware(metricsClient))
.create(IDEServiceDefinition, createChannel(config.ideServiceAddr));
});

bind(EntitlementService).to(CommunityEntitlementService).inSingletonScope();
Expand Down

0 comments on commit c4c6554

Please sign in to comment.