Skip to content

Commit 3fc00e2

Browse files
committed
better logging
Signed-off-by: Clemens Vasters <[email protected]>
1 parent 97f3439 commit 3fc00e2

File tree

1 file changed

+86
-92
lines changed

1 file changed

+86
-92
lines changed

mode-s/mode_s_kafka_bridge/mode_s.py

+86-92
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
from collections import deque
2626
from confluent_kafka import Producer
2727

28-
if sys.gettrace() is not None:
29-
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
30-
else:
31-
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
32-
3328
logger = logging.getLogger(__name__)
29+
logger.handlers = []
30+
logger.setLevel(logging.DEBUG if sys.gettrace() else logging.INFO)
31+
32+
stream_handler = logging.StreamHandler(sys.stdout)
33+
stream_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
34+
logger.addHandler(stream_handler)
35+
logger.propagate = False
3436

3537

3638
class ADSBClient(TcpClient):
@@ -62,75 +64,78 @@ def handle_messages(self, messages):
6264
return
6365
msgs = []
6466
for msg, ts in messages:
65-
raw_msg = bytes.fromhex(msg)
66-
if len(raw_msg) < 7:
67-
continue
68-
ts_ms = int(ts * 1000)
69-
df = pms.df(msg)
70-
icao = pms.icao(msg)
71-
dbfs_rssi = None
72-
raw_rssi = raw_msg[6]
73-
if raw_rssi > 0:
74-
rssi_ratio = raw_rssi / 255
75-
signal_level = rssi_ratio ** 2
76-
dbfs_rssi = round(10 * math.log10(signal_level), 2)
77-
78-
record = ModeS_ADSB_Record(
79-
ts=ts_ms, icao=icao, df=df, rssi=dbfs_rssi, tc=None, bcode=None, alt=None, cs=None, sq=None, lat=None, lon=None,
80-
spd=None, ang=None, vr=None, spd_type=None, dir_src=None, vr_src=None, ws=None, wd=None, at=None, ap=None, hm=None,
81-
roll=None, trak=None, gs=None, tas=None, hd=None, ias=None, m=None, vrb=None, vri=None, emst=None, tgt=None, opst=None
82-
)
83-
if df in (17, 18):
84-
if pms.crc(msg) != 0:
67+
try:
68+
raw_msg = bytes.fromhex(msg)
69+
if len(raw_msg) < 7:
70+
logger.warning("Invalid message (too short): %s", msg)
8571
continue
86-
tc = pms.typecode(msg)
87-
record.tc = tc
88-
if 1 <= tc <= 4:
89-
record.cs = pms.adsb.callsign(msg)
90-
elif 5 <= tc <= 8:
91-
lat, lon = pms.adsb.surface_position_with_ref(msg, self.ref_lat, self.ref_lon)
92-
record.lat, record.lon = lat, lon
93-
elif 9 <= tc <= 18:
94-
record.alt = pms.adsb.altitude(msg)
95-
lat, lon = pms.adsb.airborne_position_with_ref(msg, self.ref_lat, self.ref_lon)
96-
record.lat, record.lon = lat, lon
97-
elif tc == 19:
98-
speed, angle, vr, spd_type, *extras = pms.adsb.velocity(msg)
99-
record.spd, record.ang, record.vr = speed, angle, vr
100-
record.spd_type = spd_type
101-
if len(extras) > 0:
102-
record.dir_src = extras[0]
103-
if len(extras) > 1:
104-
record.vr_src = extras[1]
105-
elif 20 <= tc <= 22:
106-
record.alt = pms.adsb.altitude(msg)
107-
lat, lon = pms.adsb.airborne_position_with_ref(msg, self.ref_lat, self.ref_lon)
108-
record.lat, record.lon = lat, lon
109-
elif df in (20, 21):
110-
bds = pms.bds.infer(msg, mrar=True)
111-
record.bcode = bds if bds else None
112-
if df == 20:
113-
record.alt = pms.common.altcode(msg)
114-
if df == 21:
115-
record.sq = str(pms.common.idcode(msg))
116-
if bds == "BDS44":
117-
ws, wd = pms.commb.wind44(msg)
118-
record.ws, record.wd = ws, wd
119-
record.at = pms.commb.temp44(msg)
120-
record.ap = pms.commb.p44(msg)
121-
record.hm = pms.commb.hum44(msg)
122-
elif bds == "BDS50":
123-
record.roll = pms.commb.roll50(msg)
124-
record.trak = pms.commb.trk50(msg)
125-
record.gs = pms.commb.gs50(msg)
126-
record.tas = pms.commb.tas50(msg)
127-
elif bds == "BDS60":
128-
record.hd = pms.commb.hdg60(msg)
129-
record.ias = pms.commb.ias60(msg)
130-
record.m = pms.commb.mach60(msg)
131-
record.vrb = pms.commb.vr60baro(msg)
132-
record.vri = pms.commb.vr60ins(msg)
133-
msgs.append(record)
72+
73+
ts_ms = int(ts * 1000)
74+
df = pms.df(msg)
75+
icao = pms.icao(msg)
76+
dbfs_rssi = None
77+
raw_rssi = raw_msg[6]
78+
if raw_rssi > 0:
79+
rssi_ratio = raw_rssi / 255
80+
signal_level = rssi_ratio ** 2
81+
dbfs_rssi = round(10 * math.log10(signal_level), 2)
82+
83+
record = ModeS_ADSB_Record(
84+
ts=ts_ms, icao=icao, df=df, rssi=dbfs_rssi, tc=None, bcode=None, alt=None, cs=None, sq=None, lat=None, lon=None,
85+
spd=None, ang=None, vr=None, spd_type=None, dir_src=None, vr_src=None, ws=None, wd=None, at=None, ap=None, hm=None,
86+
roll=None, trak=None, gs=None, tas=None, hd=None, ias=None, m=None, vrb=None, vri=None, emst=None, tgt=None, opst=None
87+
)
88+
if df in (17, 18):
89+
tc = pms.typecode(msg)
90+
record.tc = tc
91+
if 1 <= tc <= 4:
92+
record.cs = pms.adsb.callsign(msg)
93+
elif 5 <= tc <= 8:
94+
lat, lon = pms.adsb.surface_position_with_ref(msg, self.ref_lat, self.ref_lon)
95+
record.lat, record.lon = lat, lon
96+
elif 9 <= tc <= 18:
97+
record.alt = pms.adsb.altitude(msg)
98+
lat, lon = pms.adsb.airborne_position_with_ref(msg, self.ref_lat, self.ref_lon)
99+
record.lat, record.lon = lat, lon
100+
elif tc == 19:
101+
speed, angle, vr, spd_type, *extras = pms.adsb.velocity(msg)
102+
record.spd, record.ang, record.vr = speed, angle, vr
103+
record.spd_type = spd_type
104+
if len(extras) > 0:
105+
record.dir_src = extras[0]
106+
if len(extras) > 1:
107+
record.vr_src = extras[1]
108+
elif 20 <= tc <= 22:
109+
record.alt = pms.adsb.altitude(msg)
110+
lat, lon = pms.adsb.airborne_position_with_ref(msg, self.ref_lat, self.ref_lon)
111+
record.lat, record.lon = lat, lon
112+
elif df in (20, 21):
113+
bds = pms.bds.infer(msg, mrar=True)
114+
record.bcode = bds if bds else None
115+
if df == 20:
116+
record.alt = pms.common.altcode(msg)
117+
if df == 21:
118+
record.sq = str(pms.common.idcode(msg))
119+
if bds == "BDS44":
120+
ws, wd = pms.commb.wind44(msg)
121+
record.ws, record.wd = ws, wd
122+
record.at = pms.commb.temp44(msg)
123+
record.ap = pms.commb.p44(msg)
124+
record.hm = pms.commb.hum44(msg)
125+
elif bds == "BDS50":
126+
record.roll = pms.commb.roll50(msg)
127+
record.trak = pms.commb.trk50(msg)
128+
record.gs = pms.commb.gs50(msg)
129+
record.tas = pms.commb.tas50(msg)
130+
elif bds == "BDS60":
131+
record.hd = pms.commb.hdg60(msg)
132+
record.ias = pms.commb.ias60(msg)
133+
record.m = pms.commb.mach60(msg)
134+
record.vrb = pms.commb.vr60baro(msg)
135+
record.vri = pms.commb.vr60ins(msg)
136+
msgs.append(record)
137+
except Exception as e:
138+
logger.error("Invalid message: %s, error: %s", msg, e)
134139

135140
if len(msgs) > 0:
136141
bundle = Messages(messages=msgs)
@@ -164,30 +169,30 @@ async def queue_consumer(self, stop_event: threading.Event):
164169
flush_producer=False
165170
)
166171
if (datetime.now() - last_flush) > timedelta(seconds=1) or self.records_since_last_flush >= 1000:
167-
if last_info_log < datetime.now() - timedelta(minutes=5):
168-
logging.info("Messages %d, records %d, queue length is %d", messages_since_last_log, records_since_last_log, len(self.task_queue))
172+
if last_info_log < datetime.now() - timedelta(seconds=5*60):
173+
logger.info("Messages %d, records %d, queue length is %d", messages_since_last_log, records_since_last_log, len(self.task_queue))
169174
last_info_log = datetime.now()
170175
messages_since_last_log = 0
171176
records_since_last_log = 0
172177
else:
173-
logging.debug("Flushing producer, messages %d, records %d, queue length is %d", self.messages_since_last_flush, self.records_since_last_flush, len(self.task_queue))
178+
logger.debug("Flushing producer, messages %d, records %d, queue length is %d", self.messages_since_last_flush, self.records_since_last_flush, len(self.task_queue))
174179
self.producer.producer.flush()
175180
self.messages_since_last_flush = 0
176181
self.records_since_last_flush = 0
177182
last_flush = datetime.now()
178183
except asyncio.CancelledError:
179-
logging.info("Queue consumer task cancelled")
184+
logger.info("Queue consumer task cancelled")
180185
return
181186
except Exception as e:
182-
logging.error("Error sending messages: %s", e)
187+
logger.error("Error sending messages: %s", e)
183188
else:
184189
await asyncio.sleep(0.05)
185190
except asyncio.CancelledError:
186-
logging.info("Queue consumer task cancelled")
191+
logger.info("Queue consumer task cancelled")
187192
return
188193
except Exception as e:
189-
logging.error("Queue consumer task error: %s", e)
190-
raise e
194+
logger.error("Queue consumer task error: %s", e)
195+
raise e
191196

192197

193198
def parse_connection_string(connection_string: str) -> Dict[str, str]:
@@ -252,19 +257,15 @@ async def run():
252257
if args.subcommand == 'feed':
253258
# Host/port/pos checks
254259
if not args.host:
255-
logging.error("Missing required parameter: host")
256260
print("Error: Dump1090 host is required (env: DUMP1090_HOST or --host)")
257261
return
258262
if not args.port:
259-
logging.error("Missing required parameter: port")
260263
print("Error: Dump1090 port is required (env: DUMP1090_PORT or --port)")
261264
return
262265
if args.ref_lat is None:
263-
logging.error("Missing required parameter: ref_lat")
264266
print("Error: Antenna latitude is required (env: REF_LAT or --ref-lat)")
265267
return
266268
if args.ref_lon is None:
267-
logging.error("Missing required parameter: ref_lon")
268269
print("Error: Antenna longitude is required (env: REF_LON or --ref-lon)")
269270
return
270271

@@ -282,7 +283,6 @@ async def run():
282283
sasl_username = config_params.get('sasl.username')
283284
sasl_password = config_params.get('sasl.password')
284285
except ValueError as e:
285-
logging.error("Invalid connection string: %s", e)
286286
print("Error: Invalid connection string format.")
287287
return
288288
else:
@@ -292,15 +292,12 @@ async def run():
292292
sasl_password = args.sasl_password
293293

294294
if not kafka_bootstrap_servers:
295-
logging.error("Missing required parameter: kafka_bootstrap_servers")
296295
print("Error: No Kafka bootstrap servers found.")
297296
return
298297
if not kafka_topic:
299-
logging.error("Missing required parameter: kafka_topic")
300298
print("Error: No Kafka topic found.")
301299
return
302300
if not sasl_username or not sasl_password:
303-
logging.error("Missing required SASL credentials")
304301
print("Error: SASL username and password are required.")
305302
return
306303

@@ -315,7 +312,6 @@ async def run():
315312
}
316313
kafka_producer = Producer(kafka_config)
317314
except Exception as producer_err:
318-
logging.error("Failed to create Kafka producer: %s", producer_err)
319315
print("Error: Could not create Kafka producer.")
320316
return
321317

@@ -347,9 +343,7 @@ def signal_handler(signum, frame):
347343

348344
except KeyboardInterrupt:
349345
print("Interrupted")
350-
logging.info("Application interrupted by user.")
351346
except Exception as e:
352-
logging.error("Unhandled startup error: %s", e)
353347
print(f"Error: {e}")
354348

355349
def main():

0 commit comments

Comments
 (0)