Logging๏
FlexStack includes comprehensive logging throughout its components, helping you debug issues, monitor behavior, and understand message flow in your V2X applications.
Note
Logging uses Pythonโs built-in logging module. You can configure it from simple
one-liners to detailed configuration files.
Log Levels๏
FlexStack components emit logs at different severity levels:
Level |
Constant |
When to Use |
|---|---|---|
๐ DEBUG |
|
Detailed diagnostic information (packet contents, state changes) |
โน๏ธ INFO |
|
General operational messages (service started, message sent) |
โ ๏ธ WARNING |
|
Something unexpected but recoverable happened |
โ ERROR |
|
A serious problem occurred |
๐ CRITICAL |
|
System is unusable |
Quick Start๏
One-Line Setup๏
The simplest way to enable logging:
import logging
# Show INFO and above (INFO, WARNING, ERROR, CRITICAL)
logging.basicConfig(level=logging.INFO)
# Show DEBUG and above (everything)
logging.basicConfig(level=logging.DEBUG)
Thatโs it! Youโll now see logs from all FlexStack components.
Example output:
INFO:ca_basic_service:CAM sent - Station 12345, Generation time: 5000
INFO:btp:BTP packet sent to port 2001
DEBUG:geonetworking:GeoNetworking SHB packet created
Better Formatting๏
Add timestamps and more context:
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
datefmt="%H:%M:%S",
)
Example output:
14:32:15 [INFO] ca_basic_service: CAM sent - Station 12345
14:32:15 [INFO] btp: BTP packet sent to port 2001
14:32:16 [DEBUG] link_layer: Packet received (128 bytes)
Component Loggers๏
Each FlexStack component has its own named logger:
flowchart TB
ROOT[Root Logger<br/>logging.root]
ROOT --> FAC[Facilities]
ROOT --> BTP[btp]
ROOT --> GN[geonetworking]
ROOT --> LL[link_layer]
ROOT --> SEC[security]
FAC --> CAM[ca_basic_service]
FAC --> DEN[den_service]
FAC --> VRU[vru_basic_service]
FAC --> CP[cp_service]
FAC --> LDM[local_dynamic_map]
style ROOT fill:#e3f2fd,stroke:#1565c0
Logger Names:
Logger Name |
Component |
|---|---|
|
CA Basic Service (CAMs) |
|
VRU Awareness Service (VAMs) |
|
DEN Service (DENMs) |
|
CP Service (CPMs) |
|
Local Dynamic Map |
|
BTP Router |
|
GeoNetworking Router |
|
Link Layer (RawLinkLayer, etc.) |
|
Security services |
Filtering by Component๏
Control logging for specific components:
import logging
# Set default level
logging.basicConfig(level=logging.WARNING)
# Enable DEBUG only for CA Basic Service
logging.getLogger("ca_basic_service").setLevel(logging.DEBUG)
# Enable INFO for BTP
logging.getLogger("btp").setLevel(logging.INFO)
# Silence link_layer completely
logging.getLogger("link_layer").setLevel(logging.CRITICAL)
This lets you focus on the components youโre debugging without noise from others.
Logging to File๏
Save logs to a file for later analysis:
import logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
handlers=[
logging.FileHandler("flexstack.log"), # Write to file
logging.StreamHandler(), # Also print to console
],
)
Multiple files by component:
import logging
# Main logger
logging.basicConfig(level=logging.INFO)
# Separate file for CAM logs
cam_handler = logging.FileHandler("cam_messages.log")
cam_handler.setLevel(logging.DEBUG)
logging.getLogger("ca_basic_service").addHandler(cam_handler)
# Separate file for errors only
error_handler = logging.FileHandler("errors.log")
error_handler.setLevel(logging.ERROR)
logging.getLogger().addHandler(error_handler)
Configuration File๏
For complex setups, use a configuration file:
Create logging.ini:
1[loggers]
2keys=root,ca_basic_service,vru_basic_service,btp,link_layer,local_dynamic_map
3
4[handlers]
5keys=consoleHandler,fileHandler
6
7[formatters]
8keys=detailed,simple
9
10# ======================== Loggers ======================== #
11
12[logger_root]
13level=INFO
14handlers=consoleHandler
15
16[logger_ca_basic_service]
17level=DEBUG
18handlers=fileHandler
19qualname=ca_basic_service
20propagate=1
21
22[logger_vru_basic_service]
23level=DEBUG
24handlers=
25qualname=vru_basic_service
26propagate=1
27
28[logger_btp]
29level=INFO
30handlers=
31qualname=btp
32propagate=1
33
34[logger_link_layer]
35level=WARNING
36handlers=
37qualname=link_layer
38propagate=1
39
40[logger_local_dynamic_map]
41level=DEBUG
42handlers=
43qualname=local_dynamic_map
44propagate=1
45
46# ======================== Handlers ======================== #
47
48[handler_consoleHandler]
49class=StreamHandler
50level=DEBUG
51formatter=simple
52args=(sys.stdout,)
53
54[handler_fileHandler]
55class=FileHandler
56level=DEBUG
57formatter=detailed
58args=('flexstack.log', 'w')
59
60# ======================== Formatters ======================== #
61
62[formatter_detailed]
63format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
64datefmt=%Y-%m-%d %H:%M:%S
65
66[formatter_simple]
67format=[%(levelname)s] %(name)s: %(message)s
Load the configuration:
import logging
import logging.config
logging.config.fileConfig("logging.ini", disable_existing_loggers=False)
# Now run your FlexStack application...
Common Patterns๏
Debug a Specific Issue๏
When debugging CAM generation:
import logging
# Quiet everything except what we care about
logging.basicConfig(level=logging.WARNING)
# Full debug for CAM service
logging.getLogger("ca_basic_service").setLevel(logging.DEBUG)
# Also see BTP to confirm packets are sent
logging.getLogger("btp").setLevel(logging.DEBUG)
Production Logging๏
For production deployments:
import logging
from logging.handlers import RotatingFileHandler
# Rotate logs when they reach 10MB, keep 5 backups
handler = RotatingFileHandler(
"flexstack.log",
maxBytes=10*1024*1024, # 10 MB
backupCount=5,
)
handler.setFormatter(logging.Formatter(
"%(asctime)s [%(levelname)s] %(name)s: %(message)s"
))
logging.basicConfig(
level=logging.INFO,
handlers=[handler],
)
JSON Logging๏
For log aggregation systems (ELK, Splunk):
import logging
import json
from datetime import datetime
class JSONFormatter(logging.Formatter):
def format(self, record):
return json.dumps({
"timestamp": datetime.utcnow().isoformat(),
"level": record.levelname,
"logger": record.name,
"message": record.getMessage(),
})
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.basicConfig(level=logging.INFO, handlers=[handler])
Complete Example๏
1#!/usr/bin/env python3
2"""
3FlexStack with Custom Logging
4"""
5
6import logging
7import random
8import time
9
10# ============ Configure Logging ============ #
11
12# Create formatters
13detailed_fmt = logging.Formatter(
14 "%(asctime)s [%(levelname)-8s] %(name)-20s: %(message)s",
15 datefmt="%H:%M:%S",
16)
17
18# Console handler (INFO and above)
19console = logging.StreamHandler()
20console.setLevel(logging.INFO)
21console.setFormatter(detailed_fmt)
22
23# File handler (DEBUG and above)
24file_handler = logging.FileHandler("debug.log", mode="w")
25file_handler.setLevel(logging.DEBUG)
26file_handler.setFormatter(detailed_fmt)
27
28# Configure root logger
29logging.basicConfig(level=logging.DEBUG, handlers=[console, file_handler])
30
31# Fine-tune specific loggers
32logging.getLogger("link_layer").setLevel(logging.WARNING) # Less noise
33
34# ============ FlexStack Setup ============ #
35
36from flexstack.linklayer.raw_link_layer import RawLinkLayer
37from flexstack.geonet.router import Router as GNRouter
38from flexstack.geonet.mib import MIB
39from flexstack.geonet.gn_address import GNAddress, M, ST, MID
40from flexstack.btp.router import Router as BTPRouter
41from flexstack.utils.static_location_service import ThreadStaticLocationService
42from flexstack.facilities.ca_basic_service.ca_basic_service import (
43 CooperativeAwarenessBasicService,
44)
45from flexstack.facilities.ca_basic_service.cam_transmission_management import VehicleData
46
47logger = logging.getLogger(__name__)
48
49POSITION = [41.386931, 2.112104]
50MAC_ADDRESS = bytes([(random.randint(0, 255) & 0xFE) | 0x02] +
51 [random.randint(0, 255) for _ in range(5)])
52STATION_ID = random.randint(1, 2147483647)
53
54
55def main():
56 logger.info("Starting FlexStack application...")
57
58 # Location Service
59 location_service = ThreadStaticLocationService(
60 period=1000,
61 latitude=POSITION[0],
62 longitude=POSITION[1],
63 )
64
65 # GeoNetworking
66 mib = MIB(
67 itsGnLocalGnAddr=GNAddress(
68 m=M.GN_MULTICAST,
69 st=ST.PASSENGER_CAR,
70 mid=MID(MAC_ADDRESS),
71 ),
72 )
73 gn_router = GNRouter(mib=mib, sign_service=None)
74 location_service.add_callback(gn_router.refresh_ego_position_vector)
75
76 # BTP
77 btp_router = BTPRouter(gn_router)
78 gn_router.register_indication_callback(btp_router.btp_data_indication)
79
80 # CA Basic Service
81 vehicle_data = VehicleData(
82 station_id=STATION_ID,
83 station_type=5,
84 drive_direction="forward",
85 vehicle_length={"vehicleLengthValue": 40, "vehicleLengthConfidenceIndication": "unavailable"},
86 vehicle_width=20,
87 )
88 ca_service = CooperativeAwarenessBasicService(
89 btp_router=btp_router,
90 vehicle_data=vehicle_data,
91 )
92 location_service.add_callback(
93 ca_service.cam_transmission_management.location_service_callback
94 )
95
96 # Link Layer
97 btp_router.freeze_callbacks()
98 link_layer = RawLinkLayer(
99 "lo",
100 MAC_ADDRESS,
101 receive_callback=gn_router.gn_data_indicate,
102 )
103 gn_router.link_layer = link_layer
104
105 logger.info(f"โ
Station {STATION_ID} started")
106 logger.info("๐ก Broadcasting CAMs...")
107 logger.debug(f"MAC Address: {MAC_ADDRESS.hex(':')}")
108
109 try:
110 while True:
111 time.sleep(1)
112 except KeyboardInterrupt:
113 logger.info("Shutting down...")
114
115 location_service.stop_event.set()
116 location_service.location_service_thread.join()
117 link_layer.sock.close()
118 logger.info("Goodbye!")
119
120
121if __name__ == "__main__":
122 main()
See Also๏
Python Logging Documentation โ Official Python logging guide
Getting Started โ Complete V2X tutorial
Docker Deployment โ Logging in Docker containers