Rotary Logger  1.0.2
The middleware rotary logger
Loading...
Searching...
No Matches
test_integration_writes.py
Go to the documentation of this file.
1"""
2# +==== BEGIN rotary_logger =================+
3# LOGO:
4# ..........####...####..........
5# ......###.....#.#########......
6# ....##........#.###########....
7# ...#..........#.############...
8# ...#..........#.#####.######...
9# ..#.....##....#.###..#...####..
10# .#.....#.##...#.##..##########.
11# #.....##########....##...######
12# #.....#...##..#.##..####.######
13# .#...##....##.#.##..###..#####.
14# ..#.##......#.#.####...######..
15# ..#...........#.#############..
16# ..#...........#.#############..
17# ...##.........#.############...
18# ......#.......#.#########......
19# .......#......#.########.......
20# .........#####...#####.........
21# /STOP
22# PROJECT: rotary_logger
23# FILE: test_integration_writes.py
24# CREATION DATE: 01-11-2025
25# LAST Modified: 3:41:50 04-03-2026
26# DESCRIPTION:
27# A module that provides a universal python light on iops way of logging to files your program execution.
28# /STOP
29# COPYRIGHT: (c) Asperguide
30# PURPOSE: File in charge of testing the dual channel logging where each stream is logged to it's own file.
31# // AR
32# +==== END rotary_logger =================+
33"""
34import sys
35from pathlib import Path
36from typing import Optional
37from rotary_logger import constants as CONST
38from rotary_logger.rotary_logger_cls import RotaryLogger
39
40
41def _find_log_by_folder(root: Path, folder_name: Optional[str]) -> Path:
42 """Return the first .log file under root matching the folder_name.
43
44 If folder_name is None, look for log files directly under the day
45 directory (i.e. not in stdout/stderr subfolders).
46 """
47 logs_root = root / CONST.LOG_FOLDER_BASE_NAME
48 if not logs_root.exists():
49 # older code may place directly under root
50 logs_root = root
51 # perform a shallow recursive search for .log files
52 for p in logs_root.rglob("*.log"):
53 parent = p.parent
54 # prefer files whose parent is not one of the STD subfolders
55 if parent.name not in (CONST.FOLDER_STDOUT, CONST.FOLDER_STDERR, CONST.FOLDER_STDIN, CONST.FOLDER_STDUNKNOWN):
56 return p
57 else:
58 if parent.name == folder_name:
59 return p
60 raise AssertionError(
61 f"No log file found for folder {folder_name!r} under {root}")
62
63
64def test_start_logging_split_writes(tmp_path: Path) -> None:
65 rl = RotaryLogger()
66 orig_out = sys.stdout
67 orig_err = sys.stderr
68 try:
69 rl.start_logging(log_folder=tmp_path, merged=False, log_to_file=True)
70 # write one line to each stream
71 sys.stdout.write("OUT: hello split\n")
72 sys.stderr.write("ERR: goodbye split\n")
73 # flush both
74 try:
75 sys.stdout.flush()
76 except Exception:
77 pass
78 try:
79 sys.stderr.flush()
80 except Exception:
81 pass
82 finally:
83 # restore
84 sys.stdout = orig_out
85 sys.stderr = orig_err
86
87 # locate the files
88 out_file = _find_log_by_folder(tmp_path, CONST.FOLDER_STDOUT)
89 err_file = _find_log_by_folder(tmp_path, CONST.FOLDER_STDERR)
90
91 assert out_file.exists()
92 assert err_file.exists()
93
94 out_text = out_file.read_text(encoding="utf-8")
95 err_text = err_file.read_text(encoding="utf-8")
96
97 assert "OUT: hello split" in out_text
98 assert "ERR: goodbye split" in err_text
99
100
101def test_start_logging_merged_writes(tmp_path: Path) -> None:
102 rl = RotaryLogger()
103 orig_out = sys.stdout
104 orig_err = sys.stderr
105 try:
106 rl.start_logging(log_folder=tmp_path, merged=True, log_to_file=True)
107 sys.stdout.write("OUT: hello merged\n")
108 sys.stderr.write("ERR: goodbye merged\n")
109 try:
110 sys.stdout.flush()
111 except Exception:
112 pass
113 try:
114 sys.stderr.flush()
115 except Exception:
116 pass
117 finally:
118 sys.stdout = orig_out
119 sys.stderr = orig_err
120
121 # merged logs are placed in the day directory (no stdout/stderr subfolder)
122 merged_file = _find_log_by_folder(tmp_path, None)
123 assert merged_file.exists()
124 contents = merged_file.read_text(encoding="utf-8")
125 assert "OUT: hello merged" in contents
126 assert "ERR: goodbye merged" in contents
127
128
130 """With merge_stdin=True and merged=True, stdin uses the same FileInstance as stdout/stderr."""
131 rl = RotaryLogger(merge_stdin=True)
132 rl.start_logging(log_folder=tmp_path, merged=True,
133 merge_stdin=True, log_to_file=False)
134 try:
135 assert rl.stdin_stream is not None
136 assert rl.stdout_stream is not None
137 # All three streams share the same underlying FileInstance
138 assert rl.stdin_stream.file_instance is rl.stdout_stream.file_instance
139 assert rl.stderr_stream is not None
140 assert rl.stderr_stream.file_instance is rl.stdout_stream.file_instance
141 finally:
142 rl.stop_logging()
143
144
145def test_split_mode_stdin_has_own_instance(tmp_path: Path) -> None:
146 """In split mode (merged=False), stdin gets its own FileInstance separate from stdout."""
147 rl = RotaryLogger()
148 rl.start_logging(log_folder=tmp_path, merged=False, log_to_file=False)
149 try:
150 assert rl.stdin_stream is not None
151 assert rl.stdout_stream is not None
152 # Split mode: each stream uses a different FileInstance
153 assert rl.stdin_stream.file_instance is not rl.stdout_stream.file_instance
154 assert rl.stderr_stream is not None
155 assert rl.stderr_stream.file_instance is not rl.stdout_stream.file_instance
156 finally:
157 rl.stop_logging()
None test_merge_stdin_shares_same_file_as_stdout(Path tmp_path)
None test_split_mode_stdin_has_own_instance(Path tmp_path)
None test_start_logging_split_writes(Path tmp_path)
None test_start_logging_merged_writes(Path tmp_path)
Path _find_log_by_folder(Path root, Optional[str] folder_name)