Skip to content

Commit 002050f

Browse files
authored
fix: Reduce MQTT publishing by excluding debug logging from bridge/logging (#22066)
* fix: Reduce MQTT publishing by excluding debug logging from `bridge/logging` * fix tests * fix
1 parent 394a3fb commit 002050f

File tree

6 files changed

+43
-10
lines changed

6 files changed

+43
-10
lines changed

lib/extension/bridge.ts

+21-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import data from '../util/data';
1313
import JSZip from 'jszip';
1414
import fs from 'fs';
1515
import * as zhc from 'zigbee-herdsman-converters';
16+
import winston from 'winston';
1617

1718
const requestRegex = new RegExp(`${settings.get().mqtt.base_topic}/bridge/request/(.*)`);
1819

@@ -28,6 +29,8 @@ export default class Bridge extends Extension {
2829
private coordinatorVersion: zh.CoordinatorVersion;
2930
private restartRequired = false;
3031
private lastJoinedDeviceIeeeAddr: string;
32+
private lastBridgeLoggingPayload: string;
33+
private logTransport: winston.transport;
3134
private requestLookup: {[key: string]: (message: KeyValue | string) => Promise<MQTTResponse>};
3235

3336
override async start(): Promise<void> {
@@ -59,15 +62,23 @@ export default class Bridge extends Extension {
5962
};
6063

6164
const mqtt = this.mqtt;
65+
// eslint-disable-next-line @typescript-eslint/no-this-alias
66+
const self = this;
6267
class EventTransport extends Transport {
63-
log(info: {message: string, level: string}, callback: () => void): void {
64-
const payload = stringify({message: info.message, level: info.level});
65-
mqtt.publish(`bridge/logging`, payload, {}, settings.get().mqtt.base_topic, true);
66-
callback();
68+
log(info: {message: string, level: string}, next: () => void): void {
69+
if (info.level !== 'debug') {
70+
const payload = stringify({message: info.message, level: info.level});
71+
if (payload !== self.lastBridgeLoggingPayload) {
72+
self.lastBridgeLoggingPayload = payload;
73+
mqtt.publish(`bridge/logging`, payload, {}, settings.get().mqtt.base_topic, true);
74+
}
75+
}
76+
next();
6777
}
6878
}
6979

70-
logger.addTransport(new EventTransport());
80+
this.logTransport = new EventTransport();
81+
logger.addTransport(this.logTransport);
7182

7283
this.zigbee2mqttVersion = await utils.getZigbee2MQTTVersion();
7384
this.zigbeeHerdsmanVersion = await utils.getDependencyVersion('zigbee-herdsman');
@@ -118,6 +129,11 @@ export default class Bridge extends Extension {
118129
this.eventBus.onMQTTMessage(this, this.onMQTTMessage);
119130
}
120131

132+
override async stop(): Promise<void> {
133+
super.stop();
134+
logger.removeTransport(this.logTransport);
135+
}
136+
121137
@bind async onMQTTMessage(data: eventdata.MQTTMessage): Promise<void> {
122138
const match = data.topic.match(requestRegex);
123139
const key = match?.[1]?.toLowerCase();

lib/mqtt.ts

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ export default class MQTT {
173173
this.eventBus.emitMQTTMessagePublished({topic, payload, options: {...defaultOptions, ...options}});
174174

175175
if (!this.isConnected()) {
176+
/* istanbul ignore else */
176177
if (!skipLog) {
177178
logger.error(`Not connected to MQTT server!`);
178179
logger.error(`Cannot send message: topic: '${topic}', payload: '${payload}`);

lib/util/logger.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ function addTransport(transport: winston.transport): void {
119119
logger.add(transport);
120120
}
121121

122+
function removeTransport(transport: winston.transport): void {
123+
logger.remove(transport);
124+
}
125+
122126
// TODO refactor Z2M level to 'warning' to simplify logic
123127
function getLevel(): LogLevel | 'warn' {
124128
let level = transportsToUse[0].level;
@@ -203,6 +207,6 @@ async function end(): Promise<void> {
203207
}
204208

205209
export default {
206-
init, logOutput, warning, error, info, debug, setLevel, getLevel, cleanup, addTransport, end,
210+
init, logOutput, warning, error, info, debug, setLevel, getLevel, cleanup, addTransport, end, removeTransport,
207211
winston: (): winston.Logger => logger,
208212
};

test/bridge.test.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,19 @@ describe('Bridge', () => {
107107
MQTT.publish.mockClear();
108108
logger.info.mockClear();
109109
logger.info("this is a test");
110+
logger.info("this is a test"); // Should not publish dupes
110111
expect(MQTT.publish).toHaveBeenCalledWith(
111112
'zigbee2mqtt/bridge/logging',
112113
stringify({message: 'this is a test', level: 'info'}),
113114
{ retain: false, qos: 0 },
114115
expect.any(Function)
115116
);
116-
expect(logger.info).toHaveBeenCalledTimes(1);
117+
expect(MQTT.publish).toHaveBeenCalledTimes(1);
118+
119+
// Should not publish debug logging
120+
MQTT.publish.mockClear();
121+
logger.debug("this is a test");
122+
expect(MQTT.publish).toHaveBeenCalledTimes(0);
117123
});
118124

119125
it('Shouldnt log to MQTT when not connected', async () => {

test/logger.test.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe('Logger', () => {
9090
settings.reRead();
9191
});
9292

93-
it('Add transport', () => {
93+
it('Add/remove transport', () => {
9494
class DummyTransport extends Transport {
9595
log(info, callback) {
9696
}
@@ -99,8 +99,11 @@ describe('Logger', () => {
9999
const logger = require('../lib/util/logger').default;
100100
logger.init();
101101
expect(logger.winston().transports.length).toBe(2);
102-
logger.addTransport(new DummyTransport());
102+
const transport = new DummyTransport();
103+
logger.addTransport(transport);
103104
expect(logger.winston().transports.length).toBe(3);
105+
logger.removeTransport(transport);
106+
expect(logger.winston().transports.length).toBe(2);
104107
});
105108

106109
it('Logger should be console and file by default', () => {

test/stub/logger.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
let level = 'info';
22

3-
const transports = [];
3+
let transports = [];
44

55
let transportsEnabled = false;
66
const callTransports = (level, message, namespace) => {
@@ -21,6 +21,9 @@ const mock = {
2121
logOutput: jest.fn(),
2222
add: (transport) => transports.push(transport),
2323
addTransport: (transport) => transports.push(transport),
24+
removeTransport: (transport) => {
25+
transports = transports.filter((t) => t !== transport);
26+
},
2427
setLevel: (newLevel) => {level = newLevel},
2528
getLevel: () => level,
2629
setTransportsEnabled: (value) => {transportsEnabled = value},

0 commit comments

Comments
 (0)