or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bit-timing.mdbus-operations.mdcli-tools.mdevent-system.mdfile-io.mdhardware-interfaces.mdindex.mdmessage-handling.mdperiodic-transmission.md

file-io.mddocs/

0

# File I/O and Logging

1

2

Comprehensive logging and replay system supporting multiple file formats with both reader and writer implementations. Enables recording CAN traffic for analysis, replay for testing, and conversion between different logging formats.

3

4

## Capabilities

5

6

### Generic Logging

7

8

Base logging functionality with automatic format detection and writer management.

9

10

```python { .api }

11

class Logger:

12

def __init__(self, filename: str):

13

"""

14

Create a logger that writes to the specified file.

15

Format determined by file extension.

16

17

Parameters:

18

- filename: Output file path (extension determines format)

19

"""

20

21

def __call__(self, msg: Message) -> None:

22

"""Log a message (callable interface for use with Notifier)."""

23

24

def stop(self) -> None:

25

"""Stop logging and close files."""

26

27

class BaseRotatingLogger:

28

"""Base class for size or time-based log rotation."""

29

30

class SizedRotatingLogger(BaseRotatingLogger):

31

def __init__(self, base_filename: str, max_bytes: int):

32

"""

33

Logger with automatic file rotation based on size.

34

35

Parameters:

36

- base_filename: Base name for log files

37

- max_bytes: Maximum size before rotation

38

"""

39

```

40

41

### Generic Playback

42

43

Message playback and synchronization utilities for replaying recorded CAN traffic.

44

45

```python { .api }

46

class LogReader:

47

def __init__(self, filename: str):

48

"""

49

Read messages from log file. Format auto-detected from extension.

50

51

Parameters:

52

- filename: Input file path

53

"""

54

55

def __iter__(self):

56

"""Iterate over messages in the log file."""

57

58

class MessageSync:

59

def __init__(self, messages, timestamps=None, gap=0.0001):

60

"""

61

Synchronize message playback with real-time or custom timing.

62

63

Parameters:

64

- messages: Iterable of messages

65

- timestamps: Custom timestamp sequence

66

- gap: Minimum gap between messages (seconds)

67

"""

68

```

69

70

### ASC Format (Vector)

71

72

Vector CANalyzer/CANoe ASC log format support.

73

74

```python { .api }

75

class ASCReader:

76

def __init__(self, filename: str):

77

"""Read Vector ASC log files."""

78

79

def __iter__(self):

80

"""Iterate over messages."""

81

82

class ASCWriter:

83

def __init__(self, filename: str, channel: int = 1):

84

"""

85

Write Vector ASC log files.

86

87

Parameters:

88

- filename: Output file path

89

- channel: CAN channel number for logs

90

"""

91

92

def on_message_received(self, msg: Message) -> None:

93

"""Write message to ASC file."""

94

```

95

96

### BLF Format (Vector Binary)

97

98

Vector Binary Logging Format for high-performance logging.

99

100

```python { .api }

101

class BLFReader:

102

def __init__(self, filename: str):

103

"""Read Vector BLF (Binary Logging Format) files."""

104

105

def __iter__(self):

106

"""Iterate over messages."""

107

108

class BLFWriter:

109

def __init__(self, filename: str, channel: int = 1):

110

"""

111

Write Vector BLF files.

112

113

Parameters:

114

- filename: Output file path

115

- channel: CAN channel number

116

"""

117

118

def on_message_received(self, msg: Message) -> None:

119

"""Write message to BLF file."""

120

```

121

122

### CSV Format

123

124

Comma-separated values format for easy analysis in spreadsheet applications.

125

126

```python { .api }

127

class CSVReader:

128

def __init__(self, filename: str):

129

"""Read CSV log files with standard CAN message format."""

130

131

def __iter__(self):

132

"""Iterate over messages."""

133

134

class CSVWriter:

135

def __init__(self, filename: str):

136

"""Write CSV log files with message details in columns."""

137

138

def on_message_received(self, msg: Message) -> None:

139

"""Write message to CSV file."""

140

```

141

142

### Candump Format (Linux)

143

144

Linux SocketCAN candump/canutils log format.

145

146

```python { .api }

147

class CanutilsLogReader:

148

def __init__(self, filename: str):

149

"""Read Linux candump format log files."""

150

151

def __iter__(self):

152

"""Iterate over messages."""

153

154

class CanutilsLogWriter:

155

def __init__(self, filename: str):

156

"""Write Linux candump format log files."""

157

158

def on_message_received(self, msg: Message) -> None:

159

"""Write message in candump format."""

160

```

161

162

### MF4 Format (ASAM MDF)

163

164

ASAM Measurement Data Format version 4 for automotive measurement data.

165

166

```python { .api }

167

class MF4Reader:

168

def __init__(self, filename: str):

169

"""Read ASAM MF4 measurement files."""

170

171

def __iter__(self):

172

"""Iterate over messages."""

173

174

class MF4Writer:

175

def __init__(self, filename: str):

176

"""Write ASAM MF4 measurement files."""

177

178

def on_message_received(self, msg: Message) -> None:

179

"""Write message to MF4 file."""

180

```

181

182

### SQLite Database

183

184

SQLite database format for efficient querying and analysis.

185

186

```python { .api }

187

class SqliteReader:

188

def __init__(self, filename: str):

189

"""Read messages from SQLite database."""

190

191

def __iter__(self):

192

"""Iterate over messages."""

193

194

class SqliteWriter:

195

def __init__(self, filename: str, table_name: str = 'messages'):

196

"""

197

Write messages to SQLite database.

198

199

Parameters:

200

- filename: Database file path

201

- table_name: Table name for messages

202

"""

203

204

def on_message_received(self, msg: Message) -> None:

205

"""Write message to database."""

206

```

207

208

### TRC Format

209

210

TRC trace format support with version selection.

211

212

```python { .api }

213

class TRCFileVersion(Enum):

214

"""TRC file format versions."""

215

V1_0 = "1.0"

216

V1_1 = "1.1"

217

V2_0 = "2.0"

218

219

class TRCReader:

220

def __init__(self, filename: str):

221

"""Read TRC trace files."""

222

223

def __iter__(self):

224

"""Iterate over messages."""

225

226

class TRCWriter:

227

def __init__(self, filename: str, version: TRCFileVersion = TRCFileVersion.V2_0):

228

"""

229

Write TRC trace files.

230

231

Parameters:

232

- filename: Output file path

233

- version: TRC format version

234

"""

235

236

def on_message_received(self, msg: Message) -> None:

237

"""Write message to TRC file."""

238

```

239

240

### Console Output

241

242

Print messages to console for real-time monitoring.

243

244

```python { .api }

245

class Printer:

246

def __init__(self, filename=None):

247

"""

248

Print messages to console or file.

249

250

Parameters:

251

- filename: Optional file for output (None for stdout)

252

"""

253

254

def on_message_received(self, msg: Message) -> None:

255

"""Print message in human-readable format."""

256

```

257

258

### Format Registry

259

260

Automatic format detection and writer/reader selection.

261

262

```python { .api }

263

MESSAGE_READERS: dict[str, type]

264

"""Maps file extensions to reader classes."""

265

266

MESSAGE_WRITERS: dict[str, type]

267

"""Maps file extensions to writer classes."""

268

```

269

270

## Usage Examples

271

272

### Basic Logging

273

274

```python

275

import can

276

277

# Create bus and logger

278

bus = can.Bus(channel='can0', interface='socketcan')

279

logger = can.Logger('traffic.blf')

280

281

# Log messages manually

282

for _ in range(100):

283

msg = bus.recv(timeout=1.0)

284

if msg:

285

logger(msg)

286

287

logger.stop()

288

bus.shutdown()

289

```

290

291

### Automatic Logging with Notifier

292

293

```python

294

import can

295

import time

296

297

bus = can.Bus(channel='can0', interface='socketcan')

298

299

# Multiple loggers simultaneously

300

loggers = [

301

can.Logger('traffic.blf'), # Binary format

302

can.Logger('traffic.asc'), # ASCII format

303

can.Logger('traffic.csv'), # CSV format

304

can.Printer() # Console output

305

]

306

307

# Start logging

308

notifier = can.Notifier(bus, loggers)

309

310

# Let it log for 30 seconds

311

time.sleep(30)

312

313

# Stop logging

314

notifier.stop()

315

for logger in loggers:

316

if hasattr(logger, 'stop'):

317

logger.stop()

318

319

bus.shutdown()

320

```

321

322

### Log Playback

323

324

```python

325

import can

326

import time

327

328

# Read from log file

329

log_reader = can.LogReader('recorded_traffic.blf')

330

331

# Create playback bus

332

bus = can.Bus(channel='test', interface='virtual')

333

334

# Replay messages with original timing

335

for msg in can.MessageSync(log_reader, gap=0.0001):

336

bus.send(msg)

337

# MessageSync handles timing automatically

338

339

bus.shutdown()

340

```

341

342

### Log Conversion

343

344

```python

345

import can

346

347

# Convert between formats

348

input_reader = can.io.ASCReader('input.asc')

349

output_writer = can.io.BLFWriter('output.blf')

350

351

for msg in input_reader:

352

output_writer.on_message_received(msg)

353

354

output_writer.stop()

355

```

356

357

### Size-Based Log Rotation

358

359

```python

360

import can

361

import time

362

363

bus = can.Bus(channel='can0', interface='socketcan')

364

365

# Rotate logs every 10MB

366

rotating_logger = can.SizedRotatingLogger(

367

base_filename='can_traffic.blf',

368

max_bytes=10 * 1024 * 1024 # 10MB

369

)

370

371

notifier = can.Notifier(bus, [rotating_logger])

372

373

# Log for extended period with automatic rotation

374

time.sleep(3600) # 1 hour

375

376

notifier.stop()

377

rotating_logger.stop()

378

bus.shutdown()

379

```

380

381

### SQLite Analysis

382

383

```python

384

import can

385

import sqlite3

386

387

# Log to SQLite database

388

bus = can.Bus(channel='can0', interface='socketcan')

389

db_logger = can.SqliteWriter('can_data.db')

390

391

notifier = can.Notifier(bus, [db_logger])

392

time.sleep(60) # Log for 1 minute

393

notifier.stop()

394

db_logger.stop()

395

bus.shutdown()

396

397

# Analyze logged data

398

conn = sqlite3.connect('can_data.db')

399

cursor = conn.cursor()

400

401

# Find most common message IDs

402

cursor.execute("""

403

SELECT arbitration_id, COUNT(*) as count

404

FROM messages

405

GROUP BY arbitration_id

406

ORDER BY count DESC

407

LIMIT 10

408

""")

409

410

for row in cursor.fetchall():

411

print(f"ID: 0x{row[0]:X}, Count: {row[1]}")

412

413

conn.close()

414

```

415

416

## Types

417

418

```python { .api }

419

from typing import Dict, Type, Iterator, Optional, Any

420

from abc import ABC, abstractmethod

421

from enum import Enum

422

423

class Listener(ABC):

424

"""Base class for message listeners/loggers."""

425

426

@abstractmethod

427

def on_message_received(self, msg: Message) -> None: ...

428

429

def stop(self) -> None: ...

430

431

# Format registries

432

MESSAGE_READERS: Dict[str, Type] = {

433

'.asc': ASCReader,

434

'.blf': BLFReader,

435

'.csv': CSVReader,

436

'.log': CanutilsLogReader,

437

'.mf4': MF4Reader,

438

'.db': SqliteReader,

439

'.trc': TRCReader

440

}

441

442

MESSAGE_WRITERS: Dict[str, Type] = {

443

'.asc': ASCWriter,

444

'.blf': BLFWriter,

445

'.csv': CSVWriter,

446

'.log': CanutilsLogWriter,

447

'.mf4': MF4Writer,

448

'.db': SqliteWriter,

449

'.trc': TRCWriter

450

}

451

```