Skip to content

Commit d084eca

Browse files
authored
feat: add telemetry to cf-container-logger (#151)
1 parent 7cd4576 commit d084eca

22 files changed

+1976
-361
lines changed

.eslintrc.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@
8888
"node/shebang": "off",
8989
"node/no-deprecated-api": "warn",
9090
"no-useless-constructor": "warn",
91-
"no-return-await": "off"
91+
"no-return-await": "off",
92+
"import/extensions": ["error", "never", { "json": "always" }]
9293
},
9394

9495
"overrides": [
@@ -125,5 +126,17 @@
125126
]
126127
}
127128
}
128-
]
129+
],
130+
131+
"settings": {
132+
"import/resolver": {
133+
"typescript": {
134+
"alwaysTryTypes": true,
135+
"project": ["tsconfig.json"]
136+
},
137+
"node": {
138+
"extensions": [".js", ".ts", ".json"]
139+
}
140+
}
141+
}
129142
}

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v22.17.1
1+
v22.18.0

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ARG NODE_VERSION=22.17.1
1+
ARG NODE_VERSION=22.18.0
22
FROM node:${NODE_VERSION}-bookworm-slim AS base
33
# that workdir MUST NOT be changed because of backward compatibility with the engine <= 1.177.7
44
WORKDIR /root/cf-runtime

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# FIREBASE_AUTH_URL - the main firebase ref to authenticate on initialization
55
# FIREBASE_SECRET - the secret key to write to the firebase auth url and all future derived urls
66
# LOGGER_ID - logger id. if a container will include this id in its label, we will log it
7-
# LOG_TO_CONSOLE - by default, logging to console is disabled and only logging to a file is enabled. set this env to log to console to
87
# LISTEN_ON_EXISTING - by default, if not provided, will only listen for new containers. this will enable listening on existing containers
98

109
# Container labels

lib/@types/index.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

lib/ContainerLogger.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const EventEmitter = require('events');
22
const Q = require('q');
33
const promiseRetry = require('promise-retry');
4-
const logger = require('cf-logs').Logger('codefresh:containerLogger');
4+
const { Logger } = require('@codefresh-io/cf-telemetry/logs');
55
const CFError = require('cf-errors');
66
const { Transform } = require('stream');
77

@@ -11,6 +11,8 @@ const { LoggerStrategy } = require('./enums');
1111
// eslint-disable-next-line import/no-unresolved
1212
const { DeprecatedImagesInterceptorStream } = require('./metric/deprecated-images/deprecated-images-interceptor.stream');
1313

14+
const logger = new Logger('codefresh:containerLogger');
15+
1416
const CONTAINER_START_RETRY_TIMEOUT_SECONDS = 1;
1517
const CONTAINER_START_RETRY_LIMIT = 10;
1618
const BUFFER_SIZE = 2 * 1024 * 1024; // 2 MiB

lib/addNewMask.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
const { getServerAddress } = require('./helpers');
1+
/* eslint-disable promise/catch-or-return */
2+
3+
// ↓ Should be imported first
4+
const { terminate } = require('@codefresh-io/cf-telemetry/init');
5+
// ↓ Keep one blank line below to prevent automatic import reordering
6+
7+
const { Logger } = require('@codefresh-io/cf-telemetry/logs');
8+
const { getServerAddress, registerExitHandlers } = require('./helpers');
9+
10+
const logger = new Logger('codefresh:containerLogger:addNewMask');
211

312
const exitCodes = {
413
success: 0,
@@ -14,7 +23,7 @@ const exitCodes = {
1423
let exitWithError = true;
1524
const exitHandler = (exitCode) => {
1625
if ((!exitCode || !process.exitCode) && exitWithError) {
17-
console.warn(`Unexpected exit with code 0. Exiting with ${exitCodes.unexpectedSuccess} instead`);
26+
logger.warn(`Unexpected exit with code 0. Exiting with ${exitCodes.unexpectedSuccess} instead`);
1827
process.exitCode = exitCodes.unexpectedSuccess;
1928
}
2029
};
@@ -23,7 +32,7 @@ process.on('exit', exitHandler);
2332
async function updateMasks(secret) {
2433
try {
2534
const serverAddress = await getServerAddress();
26-
console.debug(`server address: ${serverAddress}`);
35+
logger.debug(`server address: ${serverAddress}`);
2736
const url = new URL('secrets', serverAddress);
2837

2938
// eslint-disable-next-line import/no-unresolved
@@ -34,24 +43,26 @@ async function updateMasks(secret) {
3443
});
3544

3645
if (response.statusCode === 201) {
37-
console.log(`successfully updated masks with secret: ${secret.key}`);
46+
logger.log(`successfully updated masks with secret: ${secret.key}`);
3847
exitWithError = false;
39-
process.exit(exitCodes.success);
48+
terminate().finally(() => process.exit(exitCodes.success));
4049
} else {
41-
console.error(`could not create mask for secret: ${secret.key}. Server responded with: ${response.statusCode}\n\n${response.body}`);
42-
process.exit(exitCodes.error);
50+
logger.error(`could not create mask for secret: ${secret.key}. Server responded with: ${response.statusCode}\n\n${response.body}`);
51+
terminate().finally(() => process.exit(exitCodes.error));
4352
}
4453
} catch (error) {
45-
console.error(`could not create mask for secret: ${secret.key}. Error: ${error}`);
46-
process.exit(exitCodes.error);
54+
logger.error(`could not create mask for secret: ${secret.key}. Error: ${error}`);
55+
terminate().finally(() => process.exit(exitCodes.error));
4756
}
4857
}
4958

5059
if (require.main === module) {
60+
registerExitHandlers();
61+
5162
// first argument is the secret key second argument is the secret value
5263
if (process.argv.length < 4) {
53-
console.log('not enough arguments, need secret key and secret value');
54-
process.exit(exitCodes.missingArguments);
64+
logger.log('not enough arguments, need secret key and secret value');
65+
terminate().finally(() => process.exit(exitCodes.missingArguments));
5566
}
5667
const key = process.argv[2];
5768
const value = process.argv[3];

lib/helpers.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1+
/* eslint-disable promise/catch-or-return */
2+
3+
// ↓ Should be imported first
4+
const { terminate } = require('@codefresh-io/cf-telemetry/init');
5+
// ↓ Keep one blank line below to prevent automatic import reordering
6+
17
const { stat, writeFile, readFile } = require('node:fs/promises');
28
const path = require('path');
3-
const logger = require('cf-logs').Logger('codefresh:containerLogger');
4-
const getPromiseWithResolvers = require('core-js-pure/es/promise/with-resolvers');
9+
const { Logger } = require('@codefresh-io/cf-telemetry/logs');
510
const { BuildFinishedSignalFilename } = require('./enums');
611
const { SERVER_ADDRESS_PATH } = require('./const');
712

13+
const logger = new Logger('codefresh:containerLogger');
14+
815
const checkFileInterval = 1000;
916

1017
function _watchForBuildFinishedSignal(deferred) {
@@ -19,7 +26,7 @@ function _watchForBuildFinishedSignal(deferred) {
1926
}
2027

2128
if (fileExists) {
22-
console.log(`FOUND FILE '${BuildFinishedSignalFilename}' --- engine signaling build is finished`);
29+
logger.log(`FOUND FILE '${BuildFinishedSignalFilename}' --- engine signaling build is finished`);
2330
return deferred.resolve();
2431
}
2532

@@ -28,7 +35,7 @@ function _watchForBuildFinishedSignal(deferred) {
2835
}
2936

3037
function watchForBuildFinishedSignal() {
31-
const deferred = getPromiseWithResolvers();
38+
const deferred = Promise.withResolvers();
3239

3340
_watchForBuildFinishedSignal(deferred);
3441

@@ -53,13 +60,23 @@ const getServerAddress = async () => {
5360
}
5461
};
5562

63+
/**
64+
* As `@codefresh-io/cf-telemetry/init` changes the original node.js behavior of how SIGTERM and SIGINT
65+
* signals are handled, we revert this change back to the original node.js behavior.
66+
*/
67+
const registerExitHandlers = () => {
68+
process.on('SIGTERM', () => {
69+
terminate().finally(() => process.exit(143)); // default exit code for SIGTERM
70+
});
71+
72+
process.on('SIGINT', () => {
73+
terminate().finally(() => process.exit(130)); // default exit code for SIGINT
74+
});
75+
};
76+
5677
module.exports = {
57-
/**
58-
* Polyfill of `Promise.withResolvers`, TC39 Stage 4 proposal.
59-
* @see https://github.com/tc39/proposal-promise-with-resolvers
60-
*/
61-
getPromiseWithResolvers,
6278
watchForBuildFinishedSignal,
6379
saveServerAddress,
6480
getServerAddress,
81+
registerExitHandlers,
6582
};

lib/http-server/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import fastify from 'fastify';
2-
import cfLogs from 'cf-logs';
2+
import { Logger } from '@codefresh-io/cf-telemetry/logs';
33

44
import { saveServerAddress } from '../helpers';
55

66
// eslint-disable-next-line import/no-unresolved
77
import deprecatedImagesCollector from '../metric/deprecated-images/deprecated-images.collector';
88

9-
const logger = cfLogs.Logger('codefresh:containerLogger');
9+
const logger = new Logger('codefresh:containerLogger');
1010

1111
export class HttpServer {
1212

lib/index.js

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1-
const path = require('node:path');
2-
const cflogs = require('cf-logs');
3-
4-
const loggerOptions = {
5-
filePath: path.join(__dirname, '../logs', 'logs.log'),
6-
console: process.env.LOG_TO_CONSOLE || false,
7-
consoleOptions: {
8-
timestamp() {
9-
return new Date().toISOString();
10-
}
11-
}
12-
};
13-
cflogs.init(loggerOptions);
1+
// ↓ Should be imported first
2+
require('@codefresh-io/cf-telemetry/init');
3+
// ↓ Keep one blank line below to prevent automatic import reordering
4+
5+
const otel = require('@codefresh-io/cf-telemetry/otel');
6+
const { Logger: Logs } = require('@codefresh-io/cf-telemetry/logs');
7+
const { watchForBuildFinishedSignal, registerExitHandlers } = require('./helpers');
8+
9+
registerExitHandlers();
10+
11+
const logs = new Logs('codefresh:containerLogger:index');
12+
13+
const unhandledErrorsTotal = otel.cf.getMeter().createCounter(
14+
'codefresh.unhandled_errors',
15+
{
16+
description: 'Number of unhandled errors',
17+
unit: '{unhandled_error}',
18+
valueType: otel.api.ValueType.INT,
19+
},
20+
);
1421

1522
const Logger = require('./logger');
16-
const { watchForBuildFinishedSignal } = require('./helpers');
1723

1824
const taskLoggerConfig = JSON.parse(process.env.TASK_LOGGER_CONFIG);
1925

@@ -30,24 +36,26 @@ logger.validate();
3036
logger.start();
3137

3238
process.on('beforeExit', (code) => {
33-
console.log(`beforeExit: ${code}`);
39+
logs.log(`beforeExit: ${code}`);
3440
logger.state.beforeExitCode = code;
3541
logger._writeNewState();
3642
});
3743
process.on('exit', (code) => {
38-
console.log(`exit: ${code}`);
44+
logs.log(`exit: ${code}`);
3945
logger.state.exitCode = code;
4046
logger._writeNewState();
4147
});
4248

4349
process.on('uncaughtException', (error) => {
44-
console.log(`uncaughtException: ${error}`);
50+
unhandledErrorsTotal.add(1, { 'cf.unhandled_error.type': 'uncaughtException' });
51+
logs.log(`uncaughtException: ${error}`);
4552
logger.state.uncaughtException = error;
4653
logger._writeNewState();
4754
});
4855

4956
process.on('unhandledRejection', (reason) => {
50-
console.log(`unhandledRejection: ${reason}`);
57+
unhandledErrorsTotal.add(1, { 'cf.unhandled_error.type': 'unhandledRejection' });
58+
logs.log(`unhandledRejection: ${reason}`);
5159
logger.state.unhandledRejection = reason;
5260
logger._writeNewState();
5361
});

0 commit comments

Comments
 (0)