Reduce production hot-path logging

This commit is contained in:
Ben
2026-07-11 23:52:38 -04:00
parent 4f29269fed
commit bc6f2eebd8
6 changed files with 66 additions and 4 deletions
+7
View File
@@ -31,6 +31,13 @@ API_WORKERS=4
DOCKER_LOG_MAX_SIZE=100m
DOCKER_LOG_MAX_FILES=5
# Keep high-volume production logging off by default. Enable only during a
# focused diagnostic window.
STRATUM_FANOUT_LOG_ENABLED=false
BLOCK_NOTIFICATION_TRACE_LOG_ENABLED=false
DATUM_VERBOSE_LOGGING=false
SV2_AUTH_FAILURE_LOG_ENABLED=false
# Plain TCP Stratum ports accept both SV1 JSON-RPC and SV2 Noise/binary traffic.
# Legacy/default ports mine in solo mode.
STRATUM_PORTS=3333,3332,3331,3330
+4
View File
@@ -2576,6 +2576,10 @@ export class StratumV2Client {
return;
}
if (process.env.SV2_AUTH_FAILURE_LOG_ENABLED?.toLowerCase() !== 'true') {
return;
}
const remote = this.socket.remoteAddress ?? 'unknown';
const key = `${remote}:${error.message}`;
const now = Date.now();
+11
View File
@@ -1442,6 +1442,10 @@ export class BitcoinRpcService implements OnModuleInit {
}
private logTrace(trace: BlockNotificationTrace, blockTemplate: IBlockTemplate): void {
if (!this.shouldLogBlockNotificationTrace(trace)) {
return;
}
console.log(JSON.stringify({
event: 'block_notification_trace',
eventId: trace.eventId,
@@ -1456,6 +1460,13 @@ export class BitcoinRpcService implements OnModuleInit {
}));
}
private shouldLogBlockNotificationTrace(trace: BlockNotificationTrace): boolean {
if (trace.reason === 'new_block') {
return true;
}
return process.env.BLOCK_NOTIFICATION_TRACE_LOG_ENABLED?.toLowerCase() === 'true';
}
private hasConfiguredPplnsListeners(): boolean {
return PPLNS_LISTENER_CONFIG_KEYS.some(key => {
const configured = this.configService.get<string>(key) ?? process.env[key];
+10 -4
View File
@@ -116,7 +116,7 @@ export class DatumService implements OnModuleInit {
statistics: new StratumV1ClientStatistics(this.getConfiguredDatumShareDifficulty()),
lastHashRatePersistedAt: 0,
};
console.log(`[DATUM ${state.sessionId}] connection accepted from ${socket.remoteAddress}:${socket.remotePort}`);
this.logVerbose(`[DATUM ${state.sessionId}] connection accepted from ${socket.remoteAddress}:${socket.remotePort}`);
const close = () => {
void this.destroyClient(state);
@@ -152,11 +152,11 @@ export class DatumService implements OnModuleInit {
if (protoCmd === DatumProtocolCommand.HANDSHAKE_INIT) {
const hello = state.session.openHandshake(payload);
state.userAgent = hello.userAgent || 'datum/unknown';
console.log(`[DATUM ${state.sessionId}] handshake init from ${state.userAgent}`);
this.logVerbose(`[DATUM ${state.sessionId}] handshake init from ${state.userAgent}`);
await this.writeRaw(socket, state.session.buildHandshakeResponse(hello, 'public-pool DATUM'));
console.log(`[DATUM ${state.sessionId}] handshake response sent`);
this.logVerbose(`[DATUM ${state.sessionId}] handshake response sent`);
await this.sendDatumClientConfigure(socket, state);
console.log(`[DATUM ${state.sessionId}] client configure sent`);
this.logVerbose(`[DATUM ${state.sessionId}] client configure sent`);
this.startDatumPing(socket, state);
return;
}
@@ -902,6 +902,12 @@ export class DatumService implements OnModuleInit {
return Number.isFinite(configured) && configured > 0 ? configured : DEFAULT_DATUM_SHARE_DIFFICULTY;
}
private logVerbose(message: string): void {
if (process.env.DATUM_VERBOSE_LOGGING?.toLowerCase() === 'true') {
console.log(message);
}
}
private getDatumSubmittedShareDifficulty(pow: Pick<DatumPowSubmit, 'targetByte'>): number {
if (!Number.isInteger(pow.targetByte) || pow.targetByte < 0 || pow.targetByte > 63) {
return this.getConfiguredDatumShareDifficulty();
+23
View File
@@ -176,6 +176,29 @@ describe('StratumV1Service', () => {
expect(trace.totalMs).toBeLessThan(1_000);
});
it('does not log routine non-new-block fanout unless explicitly enabled', () => {
(service as any).clients.add({
broadcastMiningJob: jest.fn().mockReturnValue({
status: 'written',
bytes: 256,
bufferedBytes: 0,
}),
});
const job = {
blockData: {
id: 'routine',
height: 900001,
jobType: 'full',
isNewBlock: false,
clearJobs: false,
},
};
(service as any).broadcastMiningJob(job);
expect(consoleLogSpy.mock.calls.some(call => call[0]?.includes('stratum_job_fanout'))).toBe(false);
});
it('reports a buffer-limited client as closed without counting an unwritten job', () => {
(service as any).clients.add({
broadcastMiningJob: jest.fn().mockReturnValue({
+11
View File
@@ -506,6 +506,10 @@ export class StratumV1Service implements OnModuleInit, OnModuleDestroy {
}
}
if (!this.shouldLogJobFanout(jobTemplate.blockData.isNewBlock, errors)) {
return;
}
console.log(JSON.stringify({
event: 'stratum_job_fanout',
eventId: jobTemplate.blockData.notificationEventId,
@@ -530,6 +534,13 @@ export class StratumV1Service implements OnModuleInit, OnModuleDestroy {
}));
}
private shouldLogJobFanout(isNewBlock: boolean, errors: number): boolean {
if (errors > 0 || isNewBlock) {
return true;
}
return process.env.STRATUM_FANOUT_LOG_ENABLED?.toLowerCase() === 'true';
}
private isBackpressureDisabled() {
return process.env.STRATUM_BACKPRESSURE_ENABLED?.toLowerCase() === 'false';
}