---
title: "Parsing CS 1.6 Server Logs (logs/L*.log)"
excerpt: "Turn logging on, understand the Half-Life log line format, and grep and awk the L*.log files to answer who connected, who said what, and who killed whom."
category: "administration"
tags: "logs, admin"
image: ""
read_time: "8 min read"
---
<p>Every CS 1.6 server can write a detailed, machine-readable log of connects, chat, kills and admin actions to <code>cstrike/logs/</code>. Most admins never turn it on until they need to answer "who did that?" a week too late. This shows how to enable logging, read the standard Half-Life log format, and extract answers with nothing more than <code>grep</code> and <code>awk</code>.</p>
<h2>1. Turn logging on</h2>
<p>Put these in <a href="/tutorials/setup-server-cfg-cs16">server.cfg</a>:</p>
<pre>log on // enable logging to cstrike/logs/
mp_logmessages 1 // include chat in the log
mp_logdetail 3 // log attacks and kills (bit 1 + bit 2)
sv_log_onefile 0 // 0 = one file per map/session, 1 = single file</pre>
<p>Files land in <code>cstrike/logs/</code> named by date, like <code>L0715001.log</code> (month, day, sequence). New files roll over on map change and at midnight, so a busy server produces many small logs — which is exactly what you want when grepping a single incident.</p>
<h2>2. Read the log line format</h2>
<p>Every line follows the Half-Life standard: a timestamp, then a quoted actor, a verb, and details. A kill looks like:</p>
<pre>L 07/15/2026 - 20:14:33: "Neo<3><STEAM_0:1:12345><CT>" killed "Smith<5><STEAM_0:0:98765><TERRORIST>" with "ak47"</pre>
<p>The actor is <code>Name<userid><authid><team></code>. Other common verbs:</p>
<ul>
<li><code>connected, address "1.2.3.4:27005"</code> — a client joined.</li>
<li><code>entered the game</code> — finished connecting.</li>
<li><code>disconnected</code> — left.</li>
<li><code>say "..."</code> and <code>say_team "..."</code> — chat.</li>
<li><code>triggered "..."</code> — bomb planted/defused, round events.</li>
</ul>
<p>Because the format is stable, tools like HLstatsX parse it directly; you can too.</p>
<h2>3. Grep for the common questions</h2>
<p>Who connected, and from what IP:</p>
<pre>grep 'connected, address' cstrike/logs/L0715*.log</pre>
<p>Everything a specific player did, by SteamID (survives name changes):</p>
<pre>grep 'STEAM_0:1:12345' cstrike/logs/L0715*.log</pre>
<p>All chat, to review an argument or a slur report:</p>
<pre>grep -E '" (say|say_team) "' cstrike/logs/*.log</pre>
<p>Grepping by SteamID rather than name is the key habit — names are trivially changed, the authid is not, which is also why <a href="/tutorials/ip-bans-vs-steamid-bans">SteamID bans</a> are the precise ones.</p>
<h2>4. awk for counts and leaderboards</h2>
<p>A quick kill leaderboard for one log — pull the killer name from each <code>killed</code> line and tally:</p>
<pre>grep '" killed "' cstrike/logs/L0715001.log \
| awk -F'"' '{print $2}' \
| sed 's/<.*//' \
| sort | uniq -c | sort -rn | head</pre>
<p>The <code>-F'"'</code> splits on quotes so field 2 is the killer's <code>Name<id><auth><team></code> block; stripping from the first <code><</code> leaves the name. Count word frequency in chat, count disconnects per hour, or filter to a time window with a timestamp <code>grep</code> — the same shape of pipeline answers most questions.</p>
<h2>5. Find admin actions and abuse</h2>
<p>AMX Mod X writes admin commands to the same logs (and to its own under <code>addons/amxmodx/logs/</code>). To audit who is banning and kicking:</p>
<pre>grep -iE 'amx_(ban|kick|slay|slap|map)' cstrike/logs/*.log</pre>
<p>This is the backbone of <a href="/tutorials/prevent-admin-abuse">preventing admin abuse</a> — the log is the record you check when a player claims an admin acted unfairly.</p>
<h2>6. Correlate an incident end to end</h2>
<p>When you need the full story of one player, chain the pipelines: pull their SteamID from the connect line, then grep every log that mentions it to reconstruct the session — when they joined, from which IP, what they said, who they killed, and whether an admin acted on them. Because the timestamp prefix is fixed-width, you can also narrow to a window with a plain string match:</p>
<pre>grep 'STEAM_0:1:12345' cstrike/logs/*.log | grep '20:1' // 20:10-20:19</pre>
<p>That two-step — identity first, then time window — answers almost every "what happened at round 12" question without any external tooling. Archive the logs off the server periodically so a busy box does not rotate the evidence away before you look.</p>
<h2>Troubleshooting</h2>
<ul>
<li><strong>No log files at all</strong> — <code>log on</code> was never set, or the <code>cstrike/logs/</code> directory is not writable by the server's user. Check permissions and the console for a log-open error.</li>
<li><strong>Chat missing from the log</strong> — <code>mp_logmessages 0</code>. Set it to 1.</li>
<li><strong>No kill/attack lines</strong> — <code>mp_logdetail 0</code>. Use <code>3</code> for attacks and kills.</li>
<li><strong>One giant file instead of many</strong> — <code>sv_log_onefile 1</code>. That is fine, but grep by date range instead of by filename.</li>
<li><strong>Wrong timezone in timestamps</strong> — the log uses the server host's local time; set the box's timezone if it matters for correlating reports.</li>
</ul>
<h2>Verification</h2>
<p>Trigger something and confirm it lands. Join the server, type a test line in chat, then:</p>
<pre>tail -f cstrike/logs/L0715001.log</pre>
<p>You should see your <code>say</code> line appear live with your name, userid and SteamID. Kill a bot and confirm a <code>killed ... with</code> line shows up. Once you trust the logs are complete, keep them — disk is cheap and the one time you need to prove what happened, only the log can.</p>