66import pathlib
77from abc import ABC , abstractmethod
88from datetime import datetime
9- from typing import (
10- Any ,
11- Optional ,
12- Callable ,
13- cast ,
14- Type ,
15- )
9+ import gzip
10+ from typing import Any , Optional , Callable , TextIO , Type , Tuple , Union , cast
11+
1612from types import TracebackType
1713
1814from typing_extensions import Literal
2117from ..message import Message
2218from ..listener import Listener
2319from .generic import BaseIOHandler , FileIOMessageWriter
24- from .asc import ASCWriter , GzipASCWriter
20+ from .asc import ASCWriter
2521from .blf import BLFWriter
2622from .canutils import CanutilsLogWriter
2723from .csv import CSVWriter
@@ -34,15 +30,18 @@ class Logger(BaseIOHandler, Listener): # pylint: disable=abstract-method
3430 """
3531 Logs CAN messages to a file.
3632
37- The format is determined from the file format which can be one of:
33+ The format is determined from the file suffix which can be one of:
3834 * .asc: :class:`can.ASCWriter`
39- * .asc.gz: :class:`can.CompressedASCWriter`
4035 * .blf :class:`can.BLFWriter`
4136 * .csv: :class:`can.CSVWriter`
4237 * .db: :class:`can.SqliteWriter`
4338 * .log :class:`can.CanutilsLogWriter`
4439 * .txt :class:`can.Printer`
4540
41+ Any of these formats can be used with gzip compression by appending
42+ the suffix .gz (e.g. filename.asc.gz). However, third-party tools might not
43+ be able to read these files.
44+
4645 The **filename** may also be *None*, to fall back to :class:`can.Printer`.
4746
4847 The log files may be incomplete until `stop()` is called due to buffering.
@@ -55,7 +54,6 @@ class Logger(BaseIOHandler, Listener): # pylint: disable=abstract-method
5554 fetched_plugins = False
5655 message_writers = {
5756 ".asc" : ASCWriter ,
58- ".asc.gz" : GzipASCWriter ,
5957 ".blf" : BLFWriter ,
6058 ".csv" : CSVWriter ,
6159 ".db" : SqliteWriter ,
@@ -85,7 +83,11 @@ def __new__( # type: ignore
8583 )
8684 Logger .fetched_plugins = True
8785
88- suffix = "" .join (s .lower () for s in pathlib .PurePath (filename ).suffixes )
86+ suffix = pathlib .PurePath (filename ).suffix .lower ()
87+
88+ if suffix == ".gz" :
89+ suffix , filename = Logger .compress (filename )
90+
8991 try :
9092 return cast (
9193 Listener , Logger .message_writers [suffix ](filename , * args , ** kwargs )
@@ -95,6 +97,17 @@ def __new__( # type: ignore
9597 f'No write support for this unknown log format "{ suffix } "'
9698 ) from None
9799
100+ @staticmethod
101+ def compress (filename : StringPathLike ) -> Tuple [str , Union [str , Any ]]:
102+ """
103+ Return the suffix and io object of the decompressed file.
104+ File will automatically recompress upon close.
105+ """
106+ real_suffix = pathlib .Path (filename ).suffixes [- 2 ].lower ()
107+ mode = "ab" if real_suffix == ".blf" else "at"
108+
109+ return real_suffix , gzip .open (filename , mode )
110+
98111 def on_message_received (self , msg : Message ) -> None :
99112 pass
100113
0 commit comments