Skip to content

Commit

Permalink
Add OpenTelemetry (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsangmeister authored Jan 8, 2024
1 parent 4b1223c commit 90929e8
Show file tree
Hide file tree
Showing 12 changed files with 1,164 additions and 89 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ COPY --from=build /app/wait-for.sh .
COPY --from=build /app/node_modules ./node_modules

EXPOSE 9004
ENTRYPOINT [ "./entrypoint.sh" ]
ENTRYPOINT ["./entrypoint.sh"]

CMD ["node", "index.js"]
4 changes: 2 additions & 2 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ EXPOSE 9004

ENV OPENSLIDES_DEVELOPMENT 1

ENTRYPOINT [ "./entrypoint.sh" ]
CMD ["npm", "run", "dev"]
ENTRYPOINT ["./entrypoint.sh"]
CMD ["node", "node_modules/.bin/nodemon", "src/index.ts"]
4 changes: 2 additions & 2 deletions Dockerfile.test
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ EXPOSE 9004

ENV OPENSLIDES_DEVELOPMENT 1

ENTRYPOINT [ "./entrypoint.sh" ]
CMD ["npm", "run", "dev"]
ENTRYPOINT ["./entrypoint.sh"]
CMD ["node", "node_modules/.bin/nodemon", "src/index.ts"]
1,119 changes: 1,056 additions & 63 deletions auth/package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
"typescript": "^5.3.3"
},
"dependencies": {
"@opentelemetry/api": "^1.7.0",
"@opentelemetry/exporter-trace-otlp-grpc": "^0.46.0",
"@opentelemetry/instrumentation": "^0.46.0",
"@opentelemetry/instrumentation-express": "^0.34.0",
"@opentelemetry/instrumentation-http": "^0.46.0",
"@opentelemetry/sdk-node": "^0.46.0",
"argon2": "^0.31.2",
"axios": "^1.6.5",
"final-di": "^1.0.10-alpha.1",
Expand Down
10 changes: 9 additions & 1 deletion auth/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export class Config {
private static readonly VERBOSE_TRUE_FIELDS = ['1', 'true', 'on'];

public static isDevMode(): boolean {
return this.VERBOSE_TRUE_FIELDS.includes((process.env.OPENSLIDES_DEVELOPMENT || '').toLowerCase());
return this.isTruthy(process.env.OPENSLIDES_DEVELOPMENT);
}

public static isOtelEnabled(): boolean {
return this.isTruthy(process.env.OPENTELEMETRY_ENABLED);
}

private static isTruthy(value?: string): boolean {
return this.VERBOSE_TRUE_FIELDS.includes(value?.toLowerCase() || '');
}
}
33 changes: 18 additions & 15 deletions auth/src/express/controllers/public-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AnonymousException } from '../../core/exceptions/anonymous-exception';
import { anonymous } from '../../core/models/anonymous';
import { AuthServiceResponse } from '../../util/helper/definitions';
import { createResponse } from '../../util/helper/functions';
import { makeSpan } from '../../util/otel';

@RestController({
prefix: 'system/auth'
Expand Down Expand Up @@ -41,21 +42,23 @@ export class PublicController {
@Cookie(AuthHandler.COOKIE_NAME) cookieAsString: string,
@Res() res: Response
): Promise<AuthServiceResponse> {
try {
const ticket = await this._authHandler.whoAmI(cookieAsString);
res.setHeader(AuthHandler.AUTHENTICATION_HEADER, ticket.token.toString());
return createResponse();
} catch (e) {
Logger.debug('Error while who-am-i');
Logger.debug(e);
res.clearCookie(AuthHandler.COOKIE_NAME);
if (e instanceof AnonymousException) {
return createResponse(anonymous, 'anonymous');
return makeSpan('who-am-i', async () => {
try {
const ticket = await this._authHandler.whoAmI(cookieAsString);
res.setHeader(AuthHandler.AUTHENTICATION_HEADER, ticket.token.toString());
return createResponse();
} catch (e) {
Logger.debug('Error while who-am-i');
Logger.debug(e);
res.clearCookie(AuthHandler.COOKIE_NAME);
if (e instanceof AnonymousException) {
return createResponse(anonymous, 'anonymous');
}
if (e instanceof TokenExpiredError) {
return createResponse(anonymous, 'anonymous');
}
throw e;
}
if (e instanceof TokenExpiredError) {
return createResponse(anonymous, 'anonymous');
}
throw e;
}
});
}
}
9 changes: 6 additions & 3 deletions auth/src/express/controllers/secure-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AuthService } from '../../api/services/auth-service';
import { Token } from '../../core/ticket/token';
import { AuthServiceResponse } from '../../util/helper/definitions';
import { createResponse } from '../../util/helper/functions';
import { makeSpan } from '../../util/otel';
import { TicketMiddleware } from '../middleware/ticket-validator';

@RestController({
Expand Down Expand Up @@ -44,9 +45,11 @@ export class SecureController {

@OnPost('clear-all-sessions')
public async clearAllSessions(@Res() res: Response): Promise<AuthServiceResponse> {
const token = res.locals['token'] as Token;
await this._authHandler.clearAllSessions(token.userId);
return createResponse();
return makeSpan('clear-all-sessions', async () => {
const token = res.locals['token'] as Token;
await this._authHandler.clearAllSessions(token.userId);
return createResponse();
});
}

@OnPost('clear-session-by-id')
Expand Down
6 changes: 4 additions & 2 deletions auth/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import './init';
import { Request, Response } from 'express';
import { RestApplication } from 'rest-app';

import { Logger } from './api/services/logger';
import { PrivateController, PublicController, SamlController, SecureController } from './express/controllers';
import { addShutdownHook } from './util/helper/functions';

const logRequestInformation = (req: Request): void => {
Logger.log(`${req.protocol}://${req.headers.host || ''}: ${req.method} -- ${req.originalUrl}`);
Expand Down Expand Up @@ -52,8 +54,8 @@ class Server {
}

public start(): void {
process.on('SIGTERM', () => {
Logger.log('SIGTERM received, shutting down');
addShutdownHook(() => {
Logger.log('Kill signal received, shutting down');
process.exit(0);
});
this._application.start();
Expand Down
3 changes: 3 additions & 0 deletions auth/src/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { initOtel } from './util/otel';

initOtel();
6 changes: 6 additions & 0 deletions auth/src/util/helper/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ export const createResponse = <T = unknown>(
message: string = 'Action handled successfully',
success: boolean = true
): AuthServiceResponse => ({ message, success, ...data });

export const addShutdownHook = (func: () => void): void => {
['SIGINT', 'SIGTERM'].forEach(signal => {
process.on(signal, func);
});
};
51 changes: 51 additions & 0 deletions auth/src/util/otel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Span, trace } from '@opentelemetry/api';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { Resource } from '@opentelemetry/resources';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';

import { addShutdownHook } from './helper';
import { Logger } from '../api/services/logger';
import { Config } from '../config';

export const initOtel = (): void => {
if (!Config.isOtelEnabled()) {
return;
}
const provider = new NodeTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'auth'
})
});
const exporter = new OTLPTraceExporter({
url: 'http://collector:4317'
});
provider.addSpanProcessor(new BatchSpanProcessor(exporter));
provider.register();
trace.setGlobalTracerProvider(provider);
registerInstrumentations({
instrumentations: [new HttpInstrumentation(), new ExpressInstrumentation()]
});
addShutdownHook(() => {
provider.shutdown().catch(err => Logger.error(err));
});
Logger.log('OpenTelemetry initialized');
};

export const makeSpan = <F extends () => ReturnType<F>>(name: string, fn: F): ReturnType<F> => {
if (Config.isOtelEnabled()) {
return trace.getTracer('auth').startActiveSpan(name, (span: Span) => {
try {
return fn();
} finally {
span.end();
}
});
} else {
return fn();
}
};

0 comments on commit 90929e8

Please sign in to comment.