Current section

Files

Jump to
accesslog_parser lib accesslog_parser.ex
Raw

lib/accesslog_parser.ex

# credo:disable-for-this-file Credo.Check.Readability.MaxLineLength
defmodule AccessLogParser do
@moduledoc """
Parses access log lines matching a given (known) format.
## Usage
You simply call the parse method with your log line and the format it adheres to:
iex> AccessLogParser.parse(~s(1.2.3.4 - - [22/Apr/2017:15:17:39 +0200] "GET / HTTP/1.0" 200 765), :common)
%{
date: "22/Apr/2017:15:17:39",
ip: "1.2.3.4",
length: 765,
method: "GET",
path: "/",
protocol: "HTTP/1.0",
status: 200,
timezone: "+0200",
userid: "-"
}
## Formats
### Common Log Format (CLF)
- `:common`
- Apache configuration: `%h %l %u %t \\"%r\\" %>s %b`
### CLF with Virtual Host and Client
- `:common_complete`
- Apache configuration: `%v %h %l %u %t \\"%r\\" %>s %b \\"%{Referer}i\\" \\"%{User-agent}i\\"`
### CLF with Virtual Host
- `:common_vhost`
- Apache configuration: `%v %h %l %u %t \\"%r\\" %>s %b`
### NCSA extended/combined log format
- `:extended`
- Apache configuration: `%h %l %u %t \\"%r\\" %>s %b \\"%{Referer}i\\" \\"%{User-agent}i\\"`
"""
alias AccessLogParser.Parsec
@type log_format :: :common | :common_complete | :common_vhost | :extended
@doc """
Converts a given line into a map matching the defined format.
"""
@spec parse(String.t(), log_format) :: map
def parse(line, :common) do
case Parsec.common(line) do
{:ok, [ip, userid, date, timezone, method, path, protocol, status, length], _, _, _, _} ->
%{
date: date,
ip: ip,
length: length,
method: method,
path: path,
protocol: protocol,
status: status,
timezone: timezone,
userid: userid
}
_ ->
nil
end
end
def parse(line, :common_complete) do
case Parsec.common_complete(line) do
{:ok,
[
vhost,
ip,
userid,
date,
timezone,
method,
path,
protocol,
status,
length,
referrer,
user_agent
], _, _, _, _} ->
%{
date: date,
ip: ip,
length: length,
method: method,
path: path,
protocol: protocol,
referrer: referrer,
status: status,
timezone: timezone,
user_agent: user_agent,
userid: userid,
vhost: vhost
}
_ ->
nil
end
end
def parse(line, :common_vhost) do
case Parsec.common_vhost(line) do
{:ok, [vhost, ip, userid, date, timezone, method, path, protocol, status, length], _, _, _,
_} ->
%{
date: date,
ip: ip,
length: length,
method: method,
path: path,
protocol: protocol,
status: status,
timezone: timezone,
userid: userid,
vhost: vhost
}
_ ->
nil
end
end
def parse(line, :extended) do
case Parsec.extended(line) do
{:ok,
[
ip,
userid,
date,
timezone,
method,
path,
protocol,
status,
length,
referrer,
user_agent
], _, _, _, _} ->
%{
date: date,
ip: ip,
length: length,
method: method,
path: path,
protocol: protocol,
referrer: referrer,
status: status,
timezone: timezone,
user_agent: user_agent,
userid: userid
}
_ ->
nil
end
end
end