Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
4c20a27
Support minus (-) in hostnames
Feb 4, 2021
5e29f9c
Support postfix-$instance/submission/smtpd[$PID] log lines
Feb 4, 2021
23cb549
Rsyslog 8 do not add colon after PID
Feb 4, 2021
02c6496
Just skip over non compliant lines
Feb 4, 2021
76c0b4c
Point to yo000 repository
Feb 4, 2021
c205065
Flag -f to flatten output json, so it can be sent to syslog tools
Feb 4, 2021
e87e4e4
Usage update
Feb 4, 2021
ef4c596
Usage update
Feb 4, 2021
22c0349
Usage update
Feb 4, 2021
cc3d482
Usage update
Feb 4, 2021
fcf156e
Option -o to write to file
Feb 4, 2021
82ca75e
Usage : piping rsyslog to postfxi-log-parser
Feb 4, 2021
0d25a65
Support sasl auth + fixed useless capturing group in ProcessRegexpFormat
Feb 4, 2021
5b19589
Update README
Feb 4, 2021
e925489
Add size and nrcpt values
Feb 4, 2021
751c404
Renamed json field "timestamp" to "time"
Feb 5, 2021
a3fe494
Support syslog format (frame starting with <PRI>)
Feb 5, 2021
9f4797c
Get bounce Queue ID
Feb 5, 2021
f8c3e94
Support milter-reject
Feb 5, 2021
d10dd50
Bugfix : last commit broke writing to file
Feb 6, 2021
8cc2565
Moar tests
Feb 6, 2021
dd723e8
Daemonizing : Create PID file, recreate output when receiving SIGUSR1…
Feb 8, 2021
9f30737
Add deferred output as soon as it occurs, fix mutex usage when rotati…
Feb 9, 2021
e948312
Update Readme
Feb 9, 2021
80f09d1
Flush after each line (is back)
yo000 Feb 12, 2021
3d859fe
Support milter-hold
yo000 Feb 20, 2021
56ae1ae
Add specific tests for milter
yo000 Feb 20, 2021
35bc814
move milter to test-milter.log
yo000 Feb 20, 2021
d511ca0
BUGFIX : deferred was printed as an array with 1 msg
yo000 Feb 20, 2021
cc3a950
Add deferred test
yo000 Feb 20, 2021
29f3eb2
Optionally exports statistics to prometheus
yo000 Feb 20, 2021
e4aa207
Msg counters by host (useful with centralized syslog), build version …
yo000 Feb 21, 2021
25bb976
Count line_out by server
yo000 Feb 21, 2021
e13380d
Bump version
yo000 Feb 21, 2021
937af4d
Added counter for msg accepted by smtpd
Jun 23, 2021
3a32f52
dependencies update
Jun 23, 2021
78a8611
Count msg in more precisely, with nrcpt
Jun 23, 2021
2eda3e2
Test milter-reject
yo000 Apr 12, 2022
2916cd7
Periodically clean mqueue
yo000 Apr 12, 2022
bead604
Cleaning
yo000 Apr 25, 2022
c40ba78
RootCmd reorg
yo000 Jun 7, 2022
854f3fb
Accept input from TCP port with -s switch. Only 1 client supported.
yo000 Jun 7, 2022
2468993
Add version flag, remove printing it to stdout at execution time
yo000 Jun 7, 2022
eb17374
Version bump
yo000 Jun 7, 2022
6f517d2
Fixed miscomprehension of setDeadline, it now is an idle timeout of 10mn
yo000 Jun 10, 2022
25da670
BUGFIX nil pointer dereference when not using -s
yo000 Jun 15, 2022
bafcc42
Added counter for msg accepted by smtpd
yo000 Jun 23, 2021
c7200f8
dependencies update
yo000 Jun 23, 2021
d1e8df3
Count msg in more precisely, with nrcpt
yo000 Jun 23, 2021
390f456
Test milter-reject
yo000 Apr 12, 2022
ba55026
Periodically clean mqueue
yo000 Apr 12, 2022
0f636a1
Cleaning
yo000 Apr 25, 2022
b7d5843
RootCmd reorg
yo000 Jun 7, 2022
1069a13
Accept input from TCP port with -s switch. Only 1 client supported.
yo000 Jun 7, 2022
b05764b
Add version flag, remove printing it to stdout at execution time
yo000 Jun 7, 2022
3e2e7d8
Version bump
yo000 Jun 7, 2022
afdcb62
Fixed miscomprehension of setDeadline, it now is an idle timeout of 10mn
yo000 Jun 10, 2022
d3fde16
BUGFIX nil pointer dereference when not using -s
yo000 Jun 15, 2022
8c20ccc
Added counter for msg accepted by smtpd
yo000 Jun 23, 2021
95b88ed
dependencies update
yo000 Jun 23, 2021
04e4ef2
Count msg in more precisely, with nrcpt
yo000 Jun 23, 2021
e90a565
Test milter-reject
yo000 Apr 12, 2022
13f4500
Periodically clean mqueue
yo000 Apr 12, 2022
b868a5d
Cleaning
yo000 Apr 25, 2022
17e0e0a
RootCmd reorg
yo000 Jun 7, 2022
cb5a233
Accept input from TCP port with -s switch. Only 1 client supported.
yo000 Jun 7, 2022
0978ff0
Add version flag, remove printing it to stdout at execution time
yo000 Jun 7, 2022
d8c72c1
Version bump
yo000 Jun 7, 2022
a55c378
Fixed miscomprehension of setDeadline, it now is an idle timeout of 10mn
yo000 Jun 10, 2022
7b14269
BUGFIX nil pointer dereference when not using -s
yo000 Jun 15, 2022
e10d28b
Rename m to mQueue
yo000 Jun 15, 2022
3635365
Main parsing code is now in a function, ready to be put in a goroutin…
yo000 Jun 15, 2022
f807fe7
Merge branch 'master' of https://github.com/yo000/postfix-log-parser
yo000 Jun 16, 2022
8f7cd08
Add mQueue mutex, add postfixlogparser_client_count metric
yo000 Jun 16, 2022
f5dcffe
postfixlogparser_client_count is a gauge, as counter can not decrement
yo000 Jun 16, 2022
095e7c0
go routines for each TCP connection, moved locks to protect mQueue reads
yo000 Jun 17, 2022
be194e1
Version bump to 1.3a
yo000 Jun 17, 2022
2f110bd
Go fmt
yo000 Jun 17, 2022
39a99cd
Version bump to 1.3a
yo000 Jun 17, 2022
9a7cf35
Handle authentication failures + version bump
yo000 Jun 30, 2022
4e84bc2
Git merge pre1.3 to master
yo000 Jul 4, 2022
f26c9c4
bugfix: mutex lock on periodicallyCleanMQueue, version bump to 1.4
yo000 Jul 23, 2022
fc2be15
Merge branch 'pre1.3' of https://github.com/yo000/postfix-log-parser …
yo000 Jul 23, 2022
7620717
Version bump to 1.4.1 b/c dumbitude
yo000 Jul 23, 2022
ba0872a
Merge remote-tracking branch 'origin/pre1.3'
yo000 Jul 23, 2022
60cb153
Repo change
yo000 Jul 23, 2022
95658f9
mport log
yo000 Jul 23, 2022
46eee9e
version bump to 1.4.2 b/c dumbitude is intense
yo000 Jul 23, 2022
10c5389
BUGFIX: cleanMQueue was not removing messages
yo000 Oct 17, 2022
c2d76f5
RW Lock when cleanMQueue/iterating mQueue
yo000 Nov 18, 2022
6476460
Change version number
yo000 Nov 18, 2022
b67affb
Handle "reject:" logs
yo000 Jan 23, 2024
50ec39c
Fix parsing of PIDs
Dec 1, 2024
292164b
Merge pull request #1 from Sekiltoyai/fix-postfix-pid
yo000 Feb 23, 2025
ed9dbdf
Add postfix rate-limit message parsing
yo000 Feb 23, 2025
32aa919
Add postfix rate-limit message test
yo000 Feb 23, 2025
74e2d63
Move auth-failed at beginning of parseStoreAndWrite
yo000 Feb 23, 2025
6227336
Add test wanted outputs for reference
yo000 Feb 23, 2025
c00b2fc
Update dependencies
yo000 Feb 23, 2025
451fe05
Add "filter: RCPT" support"
yo000 Mar 16, 2025
ddf3d89
Fix NRcpt, add "filter: RCPT" support, show regex option
yo000 Mar 16, 2025
0d63de1
Update tests
yo000 Mar 16, 2025
b7b9a93
Remove unused filename parameter
yo000 Mar 16, 2025
eaeb0dd
Fix reject from not a fully qualified address, comments
yo000 Mar 16, 2025
25f6a14
Update tests
yo000 Mar 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.DEFAULT_GOAL := help
Owner := youyo
Owner := yo000
Name := postfix-log-parser
Repository := "github.com/$(Owner)/$(Name)"
GithubToken := ${GITHUB_TOKEN}
Expand Down Expand Up @@ -28,7 +28,7 @@ vendoring:
## Build
build:
go get
goxz -os=darwin,linux -arch=amd64 -d=pkg ./$(Name)
goxz -os=freebsd,darwin,linux -arch=amd64 -d=pkg ./$(Name)

## Release
release:
Expand Down
76 changes: 74 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@ Parse postfix log, and output json format
## Install

Place a `postfix-log-parser` command to your PATH and set an executable flag.
Download the latest release from github. https://github.com/youyo/postfix-log-parser/releases/latest
Download the latest release from github. https://github.com/yo000/postfix-log-parser/releases/latest

## Usage

Input postfix logs as os stdin.

``` console
# cat /var/log/maillog | ./postfix-log-parser
# cat /var/log/maillog | ./postfix-log-parser | jq
{
"time": "0000-10-10T15:59:29+09:00",
"hostname": "mail",
"process": "postfix/smtpd[1827]",
"queue_id": "3D74ADB7400B",
"client_hostname": "example.com",
"client_ip": "127.0.0.1",
"sasl_method": "PLAIN",
"sasl_username": "[email protected]",
"message_id": "[email protected]",
"from": "[email protected]",
"size": "1988",
"nrcpt": "1",
"messages": [
{
"time": "0000-10-10T15:59:30+09:00",
Expand All @@ -42,6 +46,70 @@ Input postfix logs as os stdin.
.
```

Use -f flag to flatten json structure:

``` console
# cat /var/log/maillog | ./postfix-log-parser -f | jq
{
"time": "0000-10-10T15:59:29+09:00",
"hostname": "mail",
"process": "postfix/smtpd[1827]",
"queue_id": "3D74ADB7400B",
"client_hostname": "example.com",
"client_ip": "127.0.0.1",
"sasl_method": "PLAIN",
"sasl_username": "[email protected]",
"message_id": "[email protected]",
"from": "[email protected]",
"size": "1988",
"nrcpt": "1",
"time_sent": "0000-10-10T15:59:30+09:00",
"to": "[email protected]",
"status": "sent",
"message": "to=<[email protected]>, relay=example.to[192.168.0.20]:25, delay=1.7, delays=0.02/0/1.7/0.06, dsn=2.0.0, status=sent (250 [Sniper] OK 1539154772 snipe-queue 10549)"
}
{
"time": "0000-10-10T15:59:29+09:00",
"hostname": "mail",
"process": "postfix/smtpd[1827]",
"queue_id": "3D74ADB7400B",
"client_hostname": "example.com",
"client_ip": "127.0.0.1",
"sasl_method": "PLAIN",
"sasl_username": "[email protected]",
"message_id": "[email protected]",
"from": "[email protected]",
"size": "1988",
"nrcpt": "1",
"time_sent": "0000-10-10T15:59:30+09:00",
"to": "[email protected]",
"status": "sent",
"message": "to=<[email protected]>, relay=example.to[192.168.0.20]:25, delay=1.7, delays=0.02/0/1.7/0.06, dsn=2.0.0, status=sent (250 [Sniper] OK 1539154772 snipe-queue 10549)"
}
.
.
.
```

Use "-o filename.json" to write output to file.

## Piping rsyslog to postfix-log-parser

You can feed syslog to postfix-log-parser by using "omprog" rsyslog module, with template "RSYSLOG_FileFormat" :
``` console
module(load="omprog")
[...]
mail.info /var/log/maillog
& action(
type="omprog"
binary="/usr/local/bin/postfix-log-parser -f -o /var/log/maillog.json"
template="RSYSLOG_FileFormat")

& stop

```


## Library usage

```
Expand Down Expand Up @@ -75,8 +143,12 @@ postfixlog.LogFormat{
Messages: "to=<[email protected]>, relay=mail.example-to.com[192.168.0.10]:25, delay=5.3, delays=0.26/0/0.31/4.7, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as C598F1B0002D)",
ClientHostname: "",
ClinetIp: "",
SaslMethod: "",
SaslUsername: "",
MessageId: "",
From: "",
Size: "",
NRcpt: "",
To: "[email protected]",
Status: "sent",
}
Expand Down
25 changes: 21 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
module github.com/youyo/postfix-log-parser
module github.com/yo000/postfix-log-parser

go 1.21

toolchain go1.23.2

require (
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3 // indirect
github.com/prometheus/client_golang v1.21.0
github.com/spf13/cobra v1.9.1
github.com/tabalt/pidfile v1.1.0
)

go 1.13
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
golang.org/x/sys v0.28.0 // indirect
google.golang.org/protobuf v1.36.1 // indirect
)
47 changes: 43 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,43 @@
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA=
github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tabalt/pidfile v1.1.0 h1:Q7qQGZ4MoAXE+rvM5tB4/eAIrawewYewByhMiPoDE50=
github.com/tabalt/pidfile v1.1.0/go.mod h1:7F1QwNrjfAApsuX4Nyah3RsbHVAdY/D9qZWp0nnJ/Uw=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
111 changes: 94 additions & 17 deletions postfix-log-parser.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
package postfixlog

import (
"errors"
"regexp"
"time"
)

const (
SyslogPri = `(?:<\d{1,3}>)?`
TimeFormat = "Jan 2 15:04:05"
TimeFormatISO8601 = "2006-01-02T15:04:05.999999-07:00"
TimeRegexpFormat = `([A-Za-z]{3}\s*[0-9]{1,2} [0-9]{2}:[0-9]{2}:[0-9]{2}|^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z))`
HostRegexpFormat = `([0-9A-Za-z\.]*)`
ProcessRegexpFormat = `(postfix/[a-z]*\[[0-9]{1,5}\])?`
// Capture group 1
TimeRegexpFormat = `([A-Za-z]{3}\s*[0-9]{1,2} [0-9]{2}:[0-9]{2}:[0-9]{2}|^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:[+-][0-2]\d:[0-5]\d|Z))`
// Capture group 2
HostRegexpFormat = `([0-9A-Za-z\-\.]*)`
// Capture group 3
ProcessRegexpFormat = `(postfix.*(?:\/[a-z]*)+\[[0-9]{1,7}\])?`
// Capture group 4
QueueIdRegexpFormat = `([0-9A-Z]*)`
MessageDetailsRegexpFormat = `((?:client=(.+)\[(.+)\])?(?:message-id=<(.+)>)?(?:from=<(.+@.+)>)?(?:to=<(.+@.+)>.*status=([a-z]+))?.*)`
RegexpFormat = TimeRegexpFormat + ` ` + HostRegexpFormat + ` ` + ProcessRegexpFormat + `: ` + QueueIdRegexpFormat + `(?:\: )?` + MessageDetailsRegexpFormat
// These are the main messages : Capture group 5 get all the following
// Capture groups 6, 7, 8, 9
ClientRegexpFormat = `(?:client=(.+)\[(.+)\](?:, sasl_method=(.+), sasl_username=(.+))?)?`
// CG 10
MessageIdRegexpFormat = `(?:message-id=<(.+)>)?`
// CG 11, 12, 13
FromRegexpFormat = `(?:from=<(.+@.+)>(?:, size=(\d+), nrcpt=(\d+))?)?`
// CG 14, 15
ToRegexpFormat = `(?:to=<(.+@.+)>.*status=([a-z]+))?`
// CG 16
SenderNDNRegexpFormat = `(?:sender non-delivery notification: ([0-9A-Z]*))?`
// CG 17, 18, 19, 20, 21
MilterRegexpFormat = `(?:(milter-.*): .* from (.+)\[(.+)\]: .*from=<(.+@.+)?> to=<(.+@.+)> .*)?`
// CG 22, 23, 24, 25
AuthentFailedRegexpFormat = `(?:warning: (.+)\[(.+)\]: SASL (.*) authentication failed: (.*))?`
// CG 26, 27, 28, 29. from regex is voluntarily lazy, b/c some senders really do not put '@' in from
PostfixRejectRegexpFormat = `(?:reject: RCPT from (.+)\[(.+)\]: [0-9]{3} [0-9\.]{5} [^;]*; from=<(.+)?> to=<(.+@[^>]+)>.*$)?`
// CG 30, 31, 32
PostfixRLimitExceedFormat = `(?:warning: Message delivery request rate limit exceeded: ([0-9]+) from (.+)\[(.+)\] for service [a-zA-Z]+)?`
// CG 33, 34, 35, 36, 37, 38
FilterRcptRegexpFormat = `(?:filter: RCPT from (.+)\[(.+)\]: <(.+@.+)?>: ([^;]+); from=<(.+@.+)?> to=<(.+@[^>]+)> proto=[^ ]+ helo=<.+>)?`
MessageDetailsRegexpFormat = `(` + ClientRegexpFormat + MessageIdRegexpFormat + FromRegexpFormat + ToRegexpFormat + SenderNDNRegexpFormat + MilterRegexpFormat + AuthentFailedRegexpFormat + PostfixRejectRegexpFormat + PostfixRLimitExceedFormat + FilterRcptRegexpFormat + `.*)`
RegexpFormat = SyslogPri + TimeRegexpFormat + ` ` + HostRegexpFormat + ` ` + ProcessRegexpFormat + `:? ` + QueueIdRegexpFormat + `(?:\: )?` + MessageDetailsRegexpFormat
)

type (
Expand All @@ -27,13 +54,18 @@ type (
Hostname string `json:"hostname"`
Process string `json:"process"`
QueueId string `json:"queue_id"`
Messages string `json:"messages"`
Message string `json:"message"`
ClientHostname string `json:"client_hostname"`
ClinetIp string `json:"client_ip"`
SaslMethod string `json:"sasl_method"`
SaslUsername string `json:"sasl_username"`
MessageId string `json:"message_id"`
From string `json:"from"`
Size string `json:"size"`
NRcpt string `json:"nrcpt"`
To string `json:"to"`
Status string `json:"status"`
BounceId string `json:"bounce_id"`
}
)

Expand All @@ -46,6 +78,10 @@ func NewPostfixLog() *PostfixLog {
func (p *PostfixLog) Parse(text []byte) (LogFormat, error) {
re := p.Regexp.Copy()
group := re.FindSubmatch(text)
if len(group) == 0 {
err := errors.New("Error: Line do not match regex")
return LogFormat{}, err
}
var t time.Time
t, err := time.ParseInLocation(TimeFormat, string(group[1]), time.Local)
if err != nil {
Expand All @@ -56,17 +92,58 @@ func (p *PostfixLog) Parse(text []byte) (LogFormat, error) {
}

logFormat := LogFormat{
Time: &t,
Hostname: string(group[2]),
Process: string(group[3]),
QueueId: string(group[4]),
Messages: string(group[5]),
ClientHostname: string(group[6]),
ClinetIp: string(group[7]),
MessageId: string(group[8]),
From: string(group[9]),
To: string(group[10]),
Status: string(group[11]),
Time: &t,
Hostname: string(group[2]),
Process: string(group[3]),
QueueId: string(group[4]),
Message: string(group[5]),
SaslMethod: string(group[8]),
SaslUsername: string(group[9]),
MessageId: string(group[10]),
Size: string(group[12]),
NRcpt: string(group[13]),
BounceId: string(group[16]),
}

// Milter reject|hold put values far in the group
if len(group[17]) > 0 {
logFormat.Status = string(group[17])
logFormat.ClientHostname = string(group[18])
logFormat.ClinetIp = string(group[19])
logFormat.From = string(group[20])
logFormat.To = string(group[21])
// Authentication failure
} else if len(group[22]) > 0 {
logFormat.ClientHostname = string(group[22])
logFormat.ClinetIp = string(group[23])
logFormat.SaslMethod = string(group[24])
logFormat.Status = "auth-failed"
// postfix-reject
} else if len(group[26]) > 0 {
logFormat.ClientHostname = string(group[26])
logFormat.ClinetIp = string(group[27])
logFormat.From = string(group[28])
logFormat.To = string(group[29])
logFormat.Status = "postfix-reject"
// postfix rate-limit
} else if len(group[30]) > 0 {
logFormat.ClientHostname = string(group[31])
logFormat.ClinetIp = string(group[32])
logFormat.Status = "postfix-ratelimit"
// postfix filter RCPT
} else if len(group[33]) > 0 {
logFormat.ClientHostname = string(group[33])
logFormat.ClinetIp = string(group[34])
logFormat.From = string(group[37])
logFormat.To = string(group[38])
logFormat.Status = "postfix-filter"
// bounced by remote
} else {
logFormat.Status = string(group[15])
logFormat.ClientHostname = string(group[6])
logFormat.ClinetIp = string(group[7])
logFormat.From = string(group[11])
logFormat.To = string(group[14])
}

return logFormat, nil
Expand Down
15 changes: 0 additions & 15 deletions postfix-log-parser/cmd/execute.go

This file was deleted.

Loading