Skip to content

Commit 986ed95

Browse files
authored
FFM-12353 Reduce excessive logs (#122)
1 parent 7eac4b8 commit 986ed95

9 files changed

+364
-443
lines changed

Diff for: package-lock.json

+281-419
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@harnessio/ff-nodejs-server-sdk",
3-
"version": "1.8.3",
3+
"version": "1.8.4",
44
"description": "Feature flags SDK for NodeJS environments",
55
"main": "dist/cjs/index.js",
66
"module": "dist/esm/index.mjs",

Diff for: src/__tests__/sdk_codes.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ describe('SDK Codes', () => {
3939
['warnFailedInitAuthError', [logger]],
4040
['warnAuthFailedExceedRetries', [logger]],
4141
['warnAuthRetrying', [1, 'dummy error', logger]],
42-
['warnStreamDisconnected', ['dummy reason', logger]],
43-
['warnStreamRetrying', [4, logger]],
42+
['warnStreamDisconnectedWithRetry', ['dummy reason', 1, logger]],
4443
['warnPostMetricsFailed', ['dummy error', logger]],
4544
[
4645
'warnDefaultVariationServed',

Diff for: src/client.ts

+24-7
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,32 @@ export default class Client {
139139
this.initialize(Processor.STREAM);
140140
});
141141

142+
// Track if we've already logged the streaming error since the last successful connection
143+
let streamingErrorLogged = false;
144+
145+
// Reset the error logging flag when we connect successfully
146+
this.eventBus.on(StreamEvent.CONNECTED, () => {
147+
// Reset the streaming error logged state when we successfully connect
148+
streamingErrorLogged = false;
149+
this.pollProcessor.stop();
150+
});
151+
152+
// Handle stream retry events
142153
this.eventBus.on(StreamEvent.RETRYING, () => {
143154
this.failure = true;
144-
this.log.error(
145-
'Issue with streaming: falling back to polling while the SDK attempts to reconnect',
146-
);
155+
156+
// Only log the error message if it's the first time since the last successful connection
157+
if (!streamingErrorLogged) {
158+
this.log.error(
159+
'Issue with streaming: falling back to polling while the SDK attempts to reconnect',
160+
);
161+
streamingErrorLogged = true;
162+
} else {
163+
// Log at debug level for subsequent retries until a successful reconnection
164+
this.log.debug(
165+
'Still trying to reconnect stream, staying on polling for now',
166+
);
167+
}
147168

148169
if (!this.closing) {
149170
this.pollProcessor.start();
@@ -172,10 +193,6 @@ export default class Client {
172193
this.eventBus.emit(Event.FAILED);
173194
});
174195

175-
this.eventBus.on(StreamEvent.CONNECTED, () => {
176-
this.pollProcessor.stop();
177-
});
178-
179196
this.eventBus.on(StreamEvent.DISCONNECTED, () => {
180197
if (!this.closing) {
181198
this.pollProcessor.start();

Diff for: src/evaluator.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ export class Evaluator {
348348
target: Target,
349349
): Promise<boolean> {
350350
if (parent.prerequisites) {
351-
this.log.info(
351+
this.log.debug(
352352
'Checking pre requisites %s of parent feature %s',
353353
parent.prerequisites,
354354
parent.feature,

Diff for: src/polling.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export class PollingProcessor {
131131

132132
start(): void {
133133
if (!this.stopped) {
134-
this.log.info('PollingProcessor already started');
134+
this.log.debug('PollingProcessor already started');
135135
return;
136136
}
137137
this.log.info(

Diff for: src/sdk_codes.ts

+45-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const sdkCodes: Record<number, string> = {
2020
4001: 'Polling stopped',
2121
// SDK_STREAM_5xxx
2222
5000: 'SSE stream successfully connected',
23-
5001: 'SSE stream disconnected, reason:',
23+
5001: 'SSE stream disconnected, reason:', // When used with retrying, will combine with 5003
2424
5002: 'SSE event received',
2525
5003: 'SSE retrying to connect in',
2626
5004: 'SSE stopped',
@@ -158,14 +158,54 @@ export function warnAuthRetrying(
158158
);
159159
}
160160

161-
export function warnStreamDisconnected(reason: string, logger: Logger): void {
162-
logger.warn(getSdkErrMsg(5001, reason));
161+
// Track disconnect attempts for throttling warning logs
162+
let disconnectAttempts = 0;
163+
let lastConnectionSuccess = Date.now(); // Initialize with current time to avoid huge numbers
164+
165+
// Restart disconnect counter when connection succeeds
166+
export function restartDisconnectCounter(): void {
167+
disconnectAttempts = 0;
168+
lastConnectionSuccess = Date.now();
163169
}
164170

165-
export function warnStreamRetrying(seconds: number, logger: Logger): void {
166-
logger.warn(getSdkErrMsg(5003, `${seconds}`));
171+
// Reset disconnect counter
172+
export function resetDisconnectCounter(): void {
173+
disconnectAttempts = 0;
174+
lastConnectionSuccess = Date.now();
167175
}
168176

177+
178+
// Combined warning function for both disconnect and retry in a single message
179+
export function warnStreamDisconnectedWithRetry(reason: string, ms: number, logger: Logger): void {
180+
disconnectAttempts++;
181+
182+
// First disconnect after a successful connection - always warn
183+
// Combine both codes to create a message with both disconnect reason and retry info
184+
const combinedMessage = `${getSdkErrMsg(5001)} ${reason} - ${getSdkErrMsg(5003)} ${ms}ms`;
185+
186+
if (disconnectAttempts === 1) {
187+
logger.warn(`${combinedMessage} (subsequent logs until 10th attempt will be at DEBUG level to reduce noise)`);
188+
}
189+
else if (disconnectAttempts === 10) {
190+
const timeSince = Date.now() - lastConnectionSuccess;
191+
const timeSinceConnection = Math.floor(timeSince/1000);
192+
logger.warn(`${combinedMessage} (10th attempt, connection unstable for ${timeSinceConnection} seconds, subsequent logs will be at DEBUG level except every 50th attempt)`);
193+
}
194+
195+
else if (disconnectAttempts > 10 && disconnectAttempts % 50 === 0) {
196+
const timeSince = Date.now() - lastConnectionSuccess;
197+
const timeSinceConnection = Math.floor(timeSince/1000);
198+
const nextWarnAt = disconnectAttempts + 50;
199+
logger.warn(`${combinedMessage} (${disconnectAttempts}th attempt, connection unstable for ${timeSinceConnection} seconds, next warning at ${nextWarnAt}th attempt)`);
200+
}
201+
202+
// All other disconnect attempts - log at debug level
203+
else {
204+
logger.debug(`${combinedMessage} (attempt ${disconnectAttempts}, logging at debug level to reduce noise)`);
205+
}
206+
}
207+
208+
169209
export function warnPostMetricsFailed(reason: string, logger: Logger): void {
170210
logger.warn(getSdkErrMsg(7002, reason));
171211
}

Diff for: src/streaming.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import http, { ClientRequest } from 'http';
1010
import {
1111
debugStreamEventReceived,
1212
infoStreamStopped,
13-
warnStreamDisconnected,
14-
warnStreamRetrying,
15-
} from './sdk_codes';
13+
warnStreamDisconnectedWithRetry,
14+
resetDisconnectCounter, restartDisconnectCounter
15+
} from "./sdk_codes";
1616

1717
type FetchFunction = (
1818
identifier: string,
@@ -101,6 +101,10 @@ export class StreamProcessor {
101101

102102
const onConnected = () => {
103103
this.log.info(`SSE stream connected OK: ${url}`);
104+
105+
// Reset disconnect counter when connection succeeds
106+
restartDisconnectCounter();
107+
104108
this.retryAttempt = 0;
105109
this.readyState = StreamProcessor.CONNECTED;
106110
this.eventBus.emit(StreamEvent.CONNECTED);
@@ -111,13 +115,11 @@ export class StreamProcessor {
111115
this.retryAttempt += 1;
112116

113117
const delayMs = this.getRandomRetryDelayMs();
114-
warnStreamDisconnected(msg, this.log);
115-
warnStreamRetrying(delayMs, this.log);
118+
warnStreamDisconnectedWithRetry(msg, delayMs, this.log);
116119
this.readyState = StreamProcessor.RETRYING;
117120
this.eventBus.emit(StreamEvent.RETRYING);
118121

119122
setTimeout(() => {
120-
this.log.info('SSE retrying to connect');
121123
this.connect(url, options, onConnected, onFailed);
122124
}, delayMs);
123125
}
@@ -257,6 +259,7 @@ export class StreamProcessor {
257259
this.readyState = StreamProcessor.CLOSED;
258260
this.log.info('Closing StreamProcessor');
259261

262+
resetDisconnectCounter()
260263
this.request.destroy();
261264
this.request = undefined;
262265

Diff for: src/version.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const VERSION = '1.8.3';
1+
export const VERSION = '1.8.4';

0 commit comments

Comments
 (0)