IRC Log Parser

Paste a raw log from WeeChat, irssi, mIRC, ZNC or HexChat and get one clean timeline — or a JSON, NDJSON, CSV or Markdown export with every join, part, quit, kick, mode and topic typed.

Try:
Parsed log

About this tool

IRC clients all log the same conversation in stubbornly different ways. WeeChat writes tab-separated columns, irssi writes a bare 21:07 and its own -!- event marker, mIRC and ZNC bracket the time and say *** Joins:, HexChat writes Jan 05 21:07:33 and never records the year. This parser reads all of them, turns every line into a typed record, and gives you back one consistent result: a readable timeline, or a JSON, NDJSON, CSV or Markdown export you can hand to a script or a spreadsheet.

Everything happens on the text you paste. Nothing is uploaded, no files are read from disk, and nothing is stored — so it works fine on a private channel log or an archive from a machine you no longer have.

Worked example

An irssi log, pasted as-is, with Assume channel set to #gizza:

--- Log opened Fri Jan 05 20:00:00 2024
21:07 <alice> shipping the parser tonight
21:07 -!- bob [[email protected]] has joined #gizza
21:08  * alice waves
21:09 <bob> nice, I'll review it
21:10 -!- mode/#gizza [+o bob] by alice
21:11 -!- alice [[email protected]] has quit [Ping timeout: 240 seconds]

With the default Readable timeline output and ISO timestamps:

--- Log opened Fri Jan 05 20:00:00 2024
2024-01-05T21:07:00  <alice> shipping the parser tonight
2024-01-05T21:07:00  --> bob ([email protected]) joined #gizza
2024-01-05T21:08:00  * alice waves
2024-01-05T21:09:00  <bob> nice, I'll review it
2024-01-05T21:10:00  --  mode #gizza +o bob by alice
2024-01-05T21:11:00  <-- alice quit (Ping timeout: 240 seconds)

The log itself only carries 21:07; the date comes from the --- Log opened marker, which the parser reads and then rolls forward at every --- Day changed line.

Switch Export as to CSV and the same input becomes columns instead:

line,time,type,nick,host,channel,arg,text
1,,meta,,,#gizza,,Log opened Fri Jan 05 20:00:00 2024
2,2024-01-05T21:07:00,message,alice,,#gizza,,shipping the parser tonight
3,2024-01-05T21:07:00,join,bob,[email protected],#gizza,,
4,2024-01-05T21:08:00,action,alice,,#gizza,,waves
5,2024-01-05T21:09:00,message,bob,,#gizza,,"nice, I'll review it"
6,2024-01-05T21:10:00,mode,alice,,#gizza,+o bob,
7,2024-01-05T21:11:00,quit,alice,[email protected],#gizza,,Ping timeout: 240 seconds

The record fields

Every record has the same eight fields, whichever client wrote the log, so a script never has to care about the source format:

FieldMeaning
line1-based line number in the pasted text, so you can go back to the source
timeThe timestamp, rendered the way the Timestamps option asks for
typemessage, action, notice, join, part, quit, kick, nick, mode, topic, meta or unknown
nickWho acted — the speaker, the joiner, the person who was kicked
hostThe user@host mask, when the log recorded one
channelThe channel the line belongs to, or the Assume channel value
argThe second party or payload: the new nick, the kicker, or the mode string
textThe message, the action, the part/quit reason, or the new topic

arg exists so that a kick keeps both people (nick was kicked, arg did the kicking) and a nick change keeps both names, without inventing a different column layout per event type.

Which format should I pick?

Detect automatically is right nearly always: it scores all six timestamp grammars over the first 200 non-blank lines and takes the best fit. Pin one explicitly when a log is short, mixed, or when auto-detection guesses wrong on an unusual client. The grammar only decides how the timestamp is peeled off the front of each line — the event wording of every client (-!-, ***, -->, Joins:, Parts:, was kicked, sets mode) is understood in all modes, because clients freely borrow each other's phrasing.

Limits and edge cases

FAQ

Which clients' logs does this understand?

The six timestamp grammars cover WeeChat (2024-01-05 21:07:33 then tab-separated nick and text), irssi (a bare 21:07 or 21:07:33), mIRC, ZNC, EnergyMech and Textual ([21:07:33]), HexChat and XChat (Jan 05 21:07:33), any log written with a plain ISO date and time, and logs with no timestamps at all. On top of that, the event wording used by all of those clients is recognised in every mode, so a log that has been passed through a converter or hand-edited usually still parses.

My log only has times, not dates — how do I get real timestamps?

Put the day the log covers into Base date as YYYY-MM-DD and every time-only line is dated from it. If the log contains irssi's own --- Log opened … or --- Day changed … markers, those are read automatically and take over from that point onward, which is what makes a multi-day irssi log come out with the right date on each side of midnight. With neither, records keep a time and no date, and the ISO output falls back to 21:07:00.

How do I strip the join/part/quit noise?

Set Include to Messages only, which keeps message, action and notice lines and drops joins, parts, quits, kicks, nick changes, mode and topic changes. The reverse — Events only — is useful for auditing who was in a channel and when. To follow one person instead, put their nick in Only these nicks; a trailing * matches by prefix, so bob* follows someone across bob, bob_ and bobby.

What is the difference between JSON and NDJSON here?

JSON gives you one pretty-printed array, which is what you want when a person or a browser is going to read it. NDJSON puts one compact record on each line with no wrapping array, which is what streaming tools expect: you can pipe it straight into jq, append two logs together with cat, or read it line by line without holding the whole file in memory. The records themselves are identical.

Why did my colour codes disappear?

Strip colour and formatting codes is on by default and removes the mIRC control characters — bold, italic, underline, reverse, reset and the ^C colour pairs — plus ANSI escape sequences, because they turn into unreadable noise in a CSV cell or a JSON string. Turn it off to keep every byte exactly as logged, or turn on Keep the original line to get the untouched line alongside the cleaned fields.

Does it count who talked most or merge several log files?

No — this tool parses one pasted log into records and stops there, which keeps the output predictable. Counting messages per person, activity by hour and word frequency is a separate job, and so is stitching several days or several channels into one stream. Because every record keeps its source line number and a normalised timestamp, the CSV or NDJSON output feeds straight into whatever does the counting or merging.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool irc-log-parser "--- Log opened Fri Jan 05 20:00:00 2024
21:07 <alice> shipping the parser tonight
21:07 -!- bob [[email protected]] has joined #gizza
21:11 -!- alice [[email protected]] has quit [Ping timeout: 240 seconds]"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/irc-log-parser/?log=---%20Log%20opened%20Fri%20Jan%2005%2020%3A00%3A00%202024%0A21%3A07%20%3Calice%3E%20shipping%20the%20parser%20tonight%0A21%3A07%20-%21-%20bob%20%5B~bob%40example.net%5D%20has%20joined%20%23gizza%0A21%3A11%20-%21-%20alice%20%5B~a%40example.net%5D%20has%20quit%20%5BPing%20timeout%3A%20240%20seconds%5D&format=auto&output=timeline&date=2024-01-05%20%28for%20logs%20with%20a%20time%20only%29&time_format=iso&include=all&nicks=alice%2C%20bob%2A%20%28leave%20empty%20for%20everyone%29&channel=%23gizza%20%28for%20logs%20that%20never%20name%20it%29&strip_formatting=true&include_raw=true

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.