Skip to content

Commit 6578c04

Browse files
committed
fix publishing
1 parent f986d96 commit 6578c04

File tree

4 files changed

+187
-8
lines changed

4 files changed

+187
-8
lines changed

src/mcpcat/modules/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
LOG_PATH = "mcpcat.log" # Default log file path
33
SESSION_ID_PREFIX = "ses"
44
EVENT_ID_PREFIX = "evt"
5-
MCPCAT_API_URL = "https://api.mcpcat.com" # Default API URL for MCPCat events
5+
MCPCAT_API_URL = "https://api.mcpcat.io" # Default API URL for MCPCat events

src/mcpcat/modules/event_queue.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from concurrent.futures import ThreadPoolExecutor
1010
from typing import Any
1111

12-
from mcpcat_api import Configuration, EventsApi
13-
from mcpcat.modules.constants import MCPCAT_API_URL
12+
from mcpcat_api import ApiClient, Configuration, EventsApi
13+
from mcpcat.modules.constants import EVENT_ID_PREFIX, MCPCAT_API_URL
1414

1515
from ..types import Event, UnredactedEvent
1616
from ..utils import generate_prefixed_ksuid
@@ -33,7 +33,8 @@ def __init__(self, api_client=None):
3333
# Allow injection of api_client for testing
3434
if api_client is None:
3535
config = Configuration(host=MCPCAT_API_URL)
36-
self.api_client = EventsApi(config)
36+
api_client_instance = ApiClient(configuration=config)
37+
self.api_client = EventsApi(api_client=api_client_instance)
3738
else:
3839
self.api_client = api_client
3940

@@ -147,7 +148,7 @@ def destroy(self) -> None:
147148

148149
# Shutdown executor
149150
# Note: timeout parameter was added in Python 3.9 but removed in later versions
150-
self.executor.shutdown(wait=True)
151+
self.executor.shutdown()
151152

152153
if self.queue.qsize() > 0:
153154
write_to_log(f"Shutting down with {self.queue.qsize()} events still in queue")
@@ -184,6 +185,9 @@ def publish_event(server: Any, event: UnredactedEvent) -> None:
184185
else:
185186
event.duration = None
186187

188+
if not event.id:
189+
event.id = generate_prefixed_ksuid(EVENT_ID_PREFIX)
190+
187191
data = get_server_tracking_data(server)
188192
if not data:
189193
write_to_log("Warning: Server tracking data not found. Event will not be published.")
@@ -192,11 +196,10 @@ def publish_event(server: Any, event: UnredactedEvent) -> None:
192196
session_info = get_session_info(server, data)
193197

194198
# Create full event with all required fields
195-
# Merge event data with session info (event fields take precedence)
199+
# Merge event data with session info
196200
event_data = event.model_dump(exclude_none=True)
197201
session_data = session_info.model_dump(exclude_none=True)
198202

199-
# Event fields take precedence over session fields
200203
merged_data = {**event_data, **session_data}
201204

202205
full_event = UnredactedEvent(

tests/test_event_queue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,4 +640,4 @@ def test_destroy_python38_compatibility(mock_sleep):
640640
assert eq._shutdown is True
641641
assert eq._shutdown_event.is_set()
642642
# Should be called without timeout parameter on Python 3.8
643-
mock_executor.shutdown.assert_called_once_with(wait=True)
643+
mock_executor.shutdown.assert_called_once_with()

tests/test_logging.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
"""Tests for the logging module."""
2+
3+
import os
4+
import time
5+
from pathlib import Path
6+
7+
import pytest
8+
9+
from mcpcat.modules.constants import LOG_PATH
10+
from mcpcat.modules.logging import write_to_log
11+
12+
13+
class TestLogging:
14+
"""Test the logging functionality."""
15+
16+
def test_write_to_log_creates_file(self, tmp_path):
17+
"""Test that write_to_log creates the log file if it doesn't exist."""
18+
# Use a temporary directory for the test
19+
log_file = tmp_path / "test_mcpcat.log"
20+
21+
# Monkey patch the LOG_PATH constant
22+
import mcpcat.modules.logging
23+
original_log_path = mcpcat.modules.logging.LOG_PATH
24+
mcpcat.modules.logging.LOG_PATH = str(log_file)
25+
26+
try:
27+
# Write a test message
28+
test_message = "Test log message"
29+
write_to_log(test_message)
30+
31+
# Check that the file was created
32+
assert log_file.exists(), "Log file was not created"
33+
34+
# Read the file content
35+
content = log_file.read_text()
36+
37+
# Verify the message is in the file
38+
assert test_message in content, "Log message not found in file"
39+
40+
# Verify timestamp format (ISO format)
41+
assert "T" in content, "Timestamp not in ISO format"
42+
43+
finally:
44+
# Restore original LOG_PATH
45+
mcpcat.modules.logging.LOG_PATH = original_log_path
46+
47+
def test_write_to_log_appends_messages(self, tmp_path):
48+
"""Test that write_to_log appends to existing log file."""
49+
# Use a temporary directory for the test
50+
log_file = tmp_path / "test_mcpcat.log"
51+
52+
# Monkey patch the LOG_PATH constant
53+
import mcpcat.modules.logging
54+
original_log_path = mcpcat.modules.logging.LOG_PATH
55+
mcpcat.modules.logging.LOG_PATH = str(log_file)
56+
57+
try:
58+
# Write multiple messages
59+
messages = ["First message", "Second message", "Third message"]
60+
for msg in messages:
61+
write_to_log(msg)
62+
time.sleep(0.01) # Small delay to ensure different timestamps
63+
64+
# Read the file content
65+
content = log_file.read_text()
66+
lines = content.strip().split('\n')
67+
68+
# Verify all messages are present
69+
assert len(lines) == len(messages), f"Expected {len(messages)} lines, got {len(lines)}"
70+
71+
for i, msg in enumerate(messages):
72+
assert msg in lines[i], f"Message '{msg}' not found in line {i}"
73+
74+
# Verify messages are in chronological order
75+
timestamps = []
76+
for line in lines:
77+
# Extract timestamp from [timestamp] format
78+
timestamp = line.split('] ')[0].strip('[')
79+
timestamps.append(timestamp)
80+
81+
# Check timestamps are in ascending order
82+
assert timestamps == sorted(timestamps), "Log entries are not in chronological order"
83+
84+
finally:
85+
# Restore original LOG_PATH
86+
mcpcat.modules.logging.LOG_PATH = original_log_path
87+
88+
def test_write_to_log_handles_directory_creation(self, tmp_path):
89+
"""Test that write_to_log creates parent directories if needed."""
90+
# Use a nested directory structure
91+
log_file = tmp_path / "nested" / "dirs" / "test_mcpcat.log"
92+
93+
# Monkey patch the LOG_PATH constant
94+
import mcpcat.modules.logging
95+
original_log_path = mcpcat.modules.logging.LOG_PATH
96+
mcpcat.modules.logging.LOG_PATH = str(log_file)
97+
98+
try:
99+
# Write a test message
100+
test_message = "Test with directory creation"
101+
write_to_log(test_message)
102+
103+
# Check that the directories and file were created
104+
assert log_file.exists(), "Log file was not created in nested directory"
105+
assert test_message in log_file.read_text(), "Message not written to file"
106+
107+
finally:
108+
# Restore original LOG_PATH
109+
mcpcat.modules.logging.LOG_PATH = original_log_path
110+
111+
def test_write_to_log_silently_handles_errors(self, tmp_path, monkeypatch):
112+
"""Test that write_to_log doesn't raise exceptions on errors."""
113+
# Use a file that can't be written to
114+
log_file = tmp_path / "test_mcpcat.log"
115+
116+
# Monkey patch the LOG_PATH constant
117+
import mcpcat.modules.logging
118+
original_log_path = mcpcat.modules.logging.LOG_PATH
119+
mcpcat.modules.logging.LOG_PATH = str(log_file)
120+
121+
try:
122+
# Make the parent directory read-only to cause write failure
123+
log_file.parent.chmod(0o444)
124+
125+
# This should not raise an exception
126+
write_to_log("This should fail silently")
127+
128+
# If we get here without exception, the test passes
129+
assert True
130+
131+
finally:
132+
# Restore permissions and original LOG_PATH
133+
log_file.parent.chmod(0o755)
134+
mcpcat.modules.logging.LOG_PATH = original_log_path
135+
136+
def test_log_format(self, tmp_path):
137+
"""Test the format of log entries."""
138+
# Use a temporary directory for the test
139+
log_file = tmp_path / "test_mcpcat.log"
140+
141+
# Monkey patch the LOG_PATH constant
142+
import mcpcat.modules.logging
143+
original_log_path = mcpcat.modules.logging.LOG_PATH
144+
mcpcat.modules.logging.LOG_PATH = str(log_file)
145+
146+
try:
147+
# Write a test message
148+
test_message = "Test format validation"
149+
write_to_log(test_message)
150+
151+
# Read the log entry
152+
content = log_file.read_text().strip()
153+
154+
# Verify format: "[ISO_TIMESTAMP] MESSAGE"
155+
assert content.startswith('['), "Log entry should start with ["
156+
assert '] ' in content, "Log entry should have timestamp in brackets followed by space"
157+
158+
# Extract timestamp and message
159+
bracket_end = content.index('] ')
160+
timestamp = content[1:bracket_end] # Skip the opening bracket
161+
message = content[bracket_end + 2:] # Skip '] '
162+
163+
# Verify ISO timestamp format (YYYY-MM-DDTHH:MM:SS.ssssss)
164+
assert len(timestamp) >= 19, "Timestamp too short"
165+
assert timestamp[4] == '-', "Invalid year-month separator"
166+
assert timestamp[7] == '-', "Invalid month-day separator"
167+
assert timestamp[10] == 'T', "Invalid date-time separator"
168+
assert timestamp[13] == ':', "Invalid hour-minute separator"
169+
assert timestamp[16] == ':', "Invalid minute-second separator"
170+
171+
# Verify message
172+
assert message == test_message, "Message content doesn't match"
173+
174+
finally:
175+
# Restore original LOG_PATH
176+
mcpcat.modules.logging.LOG_PATH = original_log_path

0 commit comments

Comments
 (0)