Skip to content

Commit 7dec001

Browse files
committed
First pass on session_log fixes
1 parent 5e6378a commit 7dec001

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

netmiko/session_log.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def __init__(
1212
file_encoding: str = "utf-8",
1313
no_log: Optional[Dict[str, Any]] = None,
1414
record_writes: bool = False,
15+
slog_buffer: Optional[io.StringIO] = None,
1516
) -> None:
1617
if no_log is None:
1718
self.no_log = {}
@@ -30,6 +31,13 @@ def __init__(
3031
else:
3132
self.session_log = None
3233

34+
# In order to ensure all the no_log entries get hidden properly
35+
# we must first store everying in memory and then write out to file.
36+
# Otherwise, we might miss the data we are supposed to hide (they span
37+
# multiple reads).
38+
if slog_buffer is None:
39+
self.slog_buffer = io.StringIO()
40+
3341
# Ensures last write operations prior to disconnect are recorded.
3442
self.fin = False
3543

@@ -49,15 +57,24 @@ def open(self) -> None:
4957

5058
def close(self) -> None:
5159
"""Close the session_log file (if it is a file that we opened)."""
60+
self.flush()
5261
if self.session_log and self._session_log_close:
5362
self.session_log.close()
5463
self.session_log = None
5564

56-
def write(self, data: str) -> None:
57-
if self.session_log is not None and len(data) > 0:
58-
# Hide the password and secret in the session_log
59-
for hidden_data in self.no_log.values():
60-
data = data.replace(hidden_data, "********")
65+
def no_log_filter(self, data: str) -> str:
66+
"""Filter content from the session_log."""
67+
for hidden_data in self.no_log.values():
68+
data = data.replace(hidden_data, "********")
69+
return data
70+
71+
def flush(self) -> None:
72+
"""Force the slog_buffer to be written out to the actual file"""
73+
74+
if self.session_log is not None:
75+
self.slog_buffer.seek(0)
76+
data = self.slog_buffer.read()
77+
data = self.no_log_filter(data)
6178

6279
if isinstance(self.session_log, io.BufferedIOBase):
6380
self.session_log.write(write_bytes(data, encoding=self.file_encoding))
@@ -67,4 +84,10 @@ def write(self, data: str) -> None:
6784
assert isinstance(self.session_log, io.BufferedIOBase) or isinstance(
6885
self.session_log, io.TextIOBase
6986
)
87+
88+
# Flush the underlying file
7089
self.session_log.flush()
90+
91+
def write(self, data: str) -> None:
92+
if len(data) > 0:
93+
self.slog_buffer.write(data)

tests/test_netmiko_session_log.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ def test_unicode(device_slog):
171171
conn.session_log.write("\nTesting unicode\n")
172172
conn.session_log.write(smiley_face)
173173
conn.session_log.write(smiley_face)
174+
time.sleep(1)
175+
conn.session_log.flush()
174176

175177
file_name = device_slog["session_log"]
176178
with open(file_name, "r") as f:
@@ -241,3 +243,6 @@ def test_session_log_custom_secrets(device_slog):
241243
assert sanitize_secrets["secret3"] not in session_log
242244
if sanitize_secrets.get("supersecret") is not None:
243245
assert sanitize_secrets["supersecret"] not in session_log
246+
247+
248+
def test_session_log_no_log(device_slog):

0 commit comments

Comments
 (0)