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

logging.DEBUG

Detailed diagnostic information (packet contents, state changes)

โ„น๏ธ INFO

logging.INFO

General operational messages (service started, message sent)

โš ๏ธ WARNING

logging.WARNING

Something unexpected but recoverable happened

โŒ ERROR

logging.ERROR

A serious problem occurred

๐Ÿ’€ CRITICAL

logging.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

CA Basic Service (CAMs)

vru_basic_service

VRU Awareness Service (VAMs)

den_service

DEN Service (DENMs)

cp_service

CP Service (CPMs)

local_dynamic_map

Local Dynamic Map

btp

BTP Router

geonetworking

GeoNetworking Router

link_layer

Link Layer (RawLinkLayer, etc.)

security

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๏ƒ