Skip to content

Commit 39a9de8

Browse files
committed
Enh(viewer): Show all logs
1 parent a2f492f commit 39a9de8

5 files changed

Lines changed: 139 additions & 14 deletions

File tree

.cursor/rules/viewer.mdc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,13 @@ The application has two main pages:
353353
* **Overview table**: Shows results summary with round navigation
354354
- **Header formatting**: Column headers should show player names directly followed by "Steps" (e.g., "sonnet-4-more-prescriptive Steps"), not "Player sonnet-4-more-prescriptive Steps"
355355
- **Navigation buttons**: Each row includes a button to jump to the specific round details
356+
* **All Logs section**: Shows all available log files with individual foldouts and scroll containers
357+
- **tournament.log**: Tournament-level logging
358+
- **game.log**: Game-specific logging
359+
- **everything.log**: Combined comprehensive logging
360+
- **players/p1/player.log, players/p2/player.log**: Individual player logs for each player
361+
- Each log foldout includes a "Copy path" button and has its own scroll container with max-height of 500px for large logs
362+
- Logs are displayed in a dedicated section with proper styling and scrollbars
356363

357364
#### Rounds
358365

codeclash/viewer/app.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ class GameMetadata:
260260
metadata_file_path: str
261261
rounds: list[dict[str, Any]]
262262
agent_info: list[AgentInfo] | None = None
263+
all_logs: dict[str, dict[str, str]] | None = None # {log_type: {"content": content, "path": path}}
263264

264265

265266
def process_round_results(
@@ -367,6 +368,9 @@ def parse_game_metadata(self) -> GameMetadata:
367368
main_log = main_log_file.read_text() if main_log_file.exists() else "No tournament log found"
368369
main_log_path = str(main_log_file) if main_log_file.exists() else ""
369370

371+
# Parse all available logs
372+
all_logs = self._parse_all_logs()
373+
370374
# Parse round data - prioritize round_stats from metadata.json
371375
rounds = []
372376

@@ -418,6 +422,7 @@ def parse_game_metadata(self) -> GameMetadata:
418422
metadata_file_path=metadata_file_path,
419423
rounds=rounds,
420424
agent_info=agent_info,
425+
all_logs=all_logs,
421426
)
422427

423428
def parse_trajectory(self, player_name: str, round_num: int) -> TrajectoryInfo | None:
@@ -593,6 +598,44 @@ def analyze_line_counts(self) -> dict[str, Any]:
593598

594599
return {"all_files": all_files_list, "line_counts_by_round": line_counts_by_round}
595600

601+
def _parse_all_logs(self) -> dict[str, dict[str, str]]:
602+
"""Parse all available log files in the tournament directory"""
603+
all_logs = {}
604+
605+
# Define log files to look for
606+
log_files = {"tournament.log": "Tournament Log", "game.log": "Game Log", "everything.log": "Everything Log"}
607+
608+
# Check for main log files
609+
for log_file, display_name in log_files.items():
610+
log_path = self.log_dir / log_file
611+
if log_path.exists():
612+
try:
613+
content = log_path.read_text()
614+
all_logs[display_name] = {"content": content, "path": str(log_path)}
615+
except (OSError, UnicodeDecodeError) as e:
616+
all_logs[display_name] = {"content": f"Error reading log file: {e}", "path": str(log_path)}
617+
618+
# Check for player logs
619+
players_dir = self.log_dir / "players"
620+
if players_dir.exists():
621+
for player_dir in players_dir.iterdir():
622+
if not player_dir.is_dir():
623+
continue
624+
625+
player_name = player_dir.name
626+
player_log = player_dir / "player.log"
627+
628+
if player_log.exists():
629+
try:
630+
content = player_log.read_text()
631+
display_name = f"Player {player_name} Log"
632+
all_logs[display_name] = {"content": content, "path": str(player_log)}
633+
except (OSError, UnicodeDecodeError) as e:
634+
display_name = f"Player {player_name} Log"
635+
all_logs[display_name] = {"content": f"Error reading log file: {e}", "path": str(player_log)}
636+
637+
return all_logs
638+
596639

597640
app = Flask(__name__)
598641

codeclash/viewer/static/css/style.css

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,59 @@ details summary {
401401
padding: 1rem;
402402
}
403403

404+
/* Scrollable log containers */
405+
.log-content-container {
406+
max-height: 500px;
407+
overflow: hidden;
408+
border: 1px solid var(--border-color);
409+
border-radius: 0.375rem;
410+
background-color: var(--code-bg);
411+
}
412+
413+
.log-content-scrollable {
414+
max-height: 500px;
415+
overflow-y: auto;
416+
overflow-x: auto;
417+
padding: 1rem;
418+
margin: 0;
419+
background-color: var(--code-bg);
420+
border: none;
421+
border-radius: 0;
422+
}
423+
424+
.log-content-scrollable::-webkit-scrollbar {
425+
width: 8px;
426+
height: 8px;
427+
}
428+
429+
.log-content-scrollable::-webkit-scrollbar-track {
430+
background: var(--bg-tertiary);
431+
border-radius: 4px;
432+
}
433+
434+
.log-content-scrollable::-webkit-scrollbar-thumb {
435+
background: var(--text-muted);
436+
border-radius: 4px;
437+
}
438+
439+
.log-content-scrollable::-webkit-scrollbar-thumb:hover {
440+
background: var(--text-secondary);
441+
}
442+
443+
/* Logs section styling */
444+
.logs-section {
445+
margin-top: 2rem;
446+
padding-top: 1.5rem;
447+
border-top: 1px solid var(--border-color);
448+
}
449+
450+
.logs-section h3 {
451+
color: var(--text-primary);
452+
margin-bottom: 1rem;
453+
font-size: 1.25rem;
454+
font-weight: 600;
455+
}
456+
404457
/* Special foldout types */
405458
.round-foldout {
406459
/* Removed distracting blue border */

codeclash/viewer/templates/includes/overview.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,40 @@ <h2>📊 Overview</h2>
6464
</tbody>
6565
</table>
6666
</div>
67+
68+
<!-- Tournament Log -->
69+
<details class="foldout">
70+
<summary>
71+
📝 Tournament Log
72+
{% if metadata.main_log_path %}
73+
<button class="copy-path-btn-small" data-path="{{ metadata.main_log_path }}" title="Copy file path">
74+
📋 Copy path
75+
</button>
76+
{% endif %}
77+
</summary>
78+
<div class="log-content-container">
79+
<pre class="log-content-scrollable"><code>{{ metadata.main_log }}</code></pre>
80+
</div>
81+
</details>
82+
83+
<!-- All Other Logs -->
84+
{% if metadata.all_logs %}
85+
{% for log_name, log_data in metadata.all_logs.items() %}
86+
{% if log_name != "Tournament Log" %}
87+
<details class="foldout">
88+
<summary>
89+
📝 {{ log_name }}
90+
{% if log_data.path %}
91+
<button class="copy-path-btn-small" data-path="{{ log_data.path }}" title="Copy file path">
92+
📋 Copy path
93+
</button>
94+
{% endif %}
95+
</summary>
96+
<div class="log-content-container">
97+
<pre class="log-content-scrollable"><code>{{ log_data.content }}</code></pre>
98+
</div>
99+
</details>
100+
{% endif %}
101+
{% endfor %}
102+
{% endif %}
67103
</section>

codeclash/viewer/templates/includes/setup.html

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,4 @@ <h2>⚙️ Setup</h2>
3838
</div>
3939
</details>
4040

41-
<!-- Main Log Foldout -->
42-
<details class="foldout">
43-
<summary>
44-
📝 Tournament Log
45-
{% if metadata.main_log_path %}
46-
<button class="copy-path-btn-small" data-path="{{ metadata.main_log_path }}" title="Copy file path">
47-
📋 Copy path
48-
</button>
49-
{% endif %}
50-
</summary>
51-
<div class="log-content">
52-
<pre><code>{{ metadata.main_log }}</code></pre>
53-
</div>
54-
</details>
5541
</section>

0 commit comments

Comments
 (0)