Skip to content

Commit

Permalink
Merge pull request #8 from bgentry/timestamp_opt
Browse files Browse the repository at this point in the history
Use RFC5424 / RFC5426 syslog over UDP format
  • Loading branch information
jkvor committed Apr 5, 2013
2 parents 482b997 + dfdc836 commit c8ba043
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 37 deletions.
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
## Overview

This library writes messages formatted as per [RFC5424][rfc5424], transmitted
via UDP as described in [RFC5426][rfc5426].

### Enable UDP

Ensure that syslogd has udp sockets enabled:
[OS X](http://stackoverflow.com/questions/1185554/how-to-enable-syslogd-to-receive-udp-logs-from-routers-in-osx)
You can configure syslog-ng to receive these messages with the following directive:

syslog(transport("udp") port(514) keep_timestamp(yes));

### Build

make

### Log

0> syslog:start_link(name, tag, "localhost", 514, local0).
0> syslog:start_link(name, app_name, "localhost", 514, local0).
ok
2> syslog:send(name, "test").
ok
3> syslog:notice(name, "other test").
ok
4> syslog:send(name, "test 3", [{timestamp, os:timestamp()}]).
ok

### Logged

$ syslog
...
Tue Mar 16 18:36:48 192.168.1.101 tag[4294967295] <Info>: test
Tue Mar 16 18:36:57 192.168.1.101 tag[4294967295] <Notice>: other test
<134>1 2013-04-03T21:30:44.403394Z myhost.local app_name pid - - my log message

[rfc5424]: http://tools.ietf.org/html/rfc5424 "RFC5424 - The Syslog Protocol"
[rfc5426]: http://tools.ietf.org/html/rfc5426#section-3.1 "RFC5426 - Transmission of Syslog Messages over UDP"
2 changes: 1 addition & 1 deletion src/syslog.app.src
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{application, syslog, [
{description, "Erlang syslog client"},
{vsn, "0.1"},
{vsn, "0.2"},
{applications, [kernel, stdlib]},
{registered, []}
]}.
87 changes: 56 additions & 31 deletions src/syslog.erl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
info/1, info/2, info/3,
debug/1, debug/2, debug/3]).

-record(state, {socket, address, port, facility, tag}).
-record(state, {socket, address, port, facility, app_name}).

-define(DEFAULT_FACILITY, local0).

Expand All @@ -64,13 +64,16 @@ start_link(Name, Host, Port, Facility) when is_atom(Name), is_list(Host),
is_integer(Port), is_atom(Facility) ->
gen_server:start_link({local, Name}, ?MODULE, [?MODULE, Host, Port, Facility], []).

start_link(Name, Tag, Host, Port, Facility) when is_atom(Name), is_atom(Tag), is_list(Host),
start_link(Name, AppName, Host, Port, Facility) when is_atom(Name), is_atom(AppName), is_list(Host),
is_integer(Port), is_atom(Facility) ->
gen_server:start_link({local, Name}, ?MODULE, [Tag, Host, Port, Facility], []).
gen_server:start_link({local, Name}, ?MODULE, [AppName, Host, Port, Facility], []).

send(Msg) when is_list(Msg) ->
send(?MODULE, Msg).

send(Msg, Opts) when is_list(Msg), is_list(Opts) ->
send(?MODULE, Msg, []);

send(Name, Msg) when is_list(Msg) ->
send(Name, Msg, []).

Expand Down Expand Up @@ -162,7 +165,7 @@ debug(Name, Msg, Opts) ->
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([Tag, Host, Port, Facility]) ->
init([AppName, Host, Port, Facility]) ->
{ok, Addr} = inet:getaddr(Host, inet),
case gen_udp:open(0) of
{ok, Socket} ->
Expand All @@ -171,7 +174,7 @@ init([Tag, Host, Port, Facility]) ->
address = Addr,
port = Port,
facility = Facility,
tag = Tag
app_name = AppName
}};
{error, Reason} ->
{stop, Reason}
Expand All @@ -188,8 +191,8 @@ init([Tag, Host, Port, Facility]) ->
%%--------------------------------------------------------------------
handle_call(facility, _From, #state{facility=Facility}=State) ->
{reply, Facility, State};
handle_call(tag, _From, #state{tag=Tag}=State) ->
{reply, Tag, State}.
handle_call(app_name, _From, #state{app_name=AppName}=State) ->
{reply, AppName, State}.

%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
Expand Down Expand Up @@ -237,8 +240,16 @@ get_level(Facility, Opts) ->
Level = atom_to_level(proplists:get_value(level, Opts)),
integer_to_list((Facility * 8) + Level).

get_tag(Name) ->
case gen_server:call(Name, tag) of
get_app_name(Name) ->
case gen_server:call(Name, app_name) of
Atom when is_atom(Atom) -> atom_to_list(Atom);
List when is_list(List) -> List;
Binary when is_binary(Binary) -> Binary
end.

get_app_name(Name, Opts) ->
case proplists:get_value(app_name, Opts) of
undefined -> get_app_name(Name);
Atom when is_atom(Atom) -> atom_to_list(Atom);
List when is_list(List) -> List;
Binary when is_binary(Binary) -> Binary
Expand All @@ -256,38 +267,52 @@ get_facility(Name) ->
Facility = gen_server:call(Name, facility),
facility(Facility).

get_hostname() ->
{ok, Host} = inet:gethostname(),
Host.
get_facility(Name, Opts) ->
case proplists:get_value(facility, Opts) of
undefined -> get_facility(Name);
Facility when is_atom(Facility) -> facility(Facility);
Facility when is_integer(Facility) -> Facility
end.

get_timestamp() ->
{{_,Month,Day},{Hr,Min,Sec}} = calendar:local_time(),
StringMonth = httpd_util:month(Month),
get_hostname(Opts) ->
case proplists:get_value(hostname, Opts) of
undefined ->
{ok, Host} = inet:gethostname(),
Host;
Atom when is_atom(Atom) -> atom_to_list(Atom);
List when is_list(List) -> List;
Binary when is_binary(Binary) -> Binary
end.

StringMonth ++ " "
++ maybe_add_padding(Day) ++ " "
++ maybe_add_padding(Hr) ++ ":"
++ maybe_add_padding(Min) ++ ":"
++ maybe_add_padding(Sec).
get_timestamp(Opts) when is_list(Opts) ->
case proplists:get_value(timestamp, Opts) of
undefined -> format_timestamp(os:timestamp());
Timestamp -> format_timestamp(Timestamp)
end.

maybe_add_padding(Int) when Int < 10 ->
"0" ++ integer_to_list(Int);
maybe_add_padding(Int) ->
integer_to_list(Int).
format_timestamp(TS) ->
{{Y, M, D}, {H, MM, S}} = calendar:now_to_universal_time(TS),
US = element(3, TS),
io_lib:format("~4.10.0B-~2.10.0B-~2.10.0BT~2.10.0B:~2.10.0B:~2.10.0B.~6.10.0BZ",
[Y,M,D, H,MM,S,US]).

build_packet(Name, Msg, Opts) ->
Tag = get_tag(Name),
AppName = get_app_name(Name, Opts),
Pid = get_pid(Opts),
Hostname = get_hostname(),
Timestamp = get_timestamp(),
Hostname = get_hostname(Opts),
Timestamp = get_timestamp(Opts),

Facility = get_facility(Name),
Facility = get_facility(Name, Opts),
Level = get_level(Facility, Opts),

Packet = [
"<", Level, "> ",
Timestamp, " ", Hostname, " ",
Tag, "[", Pid, "]: ", Msg, "\n"
"<", Level, ">1 ", % syslog version 1
Timestamp, " ",
Hostname, " ",
AppName, " ",
Pid,
" - - ", % MSGID is -, STRUCTURED-DATA is -
Msg, "\n"
],

iolist_to_binary(Packet).
Expand Down

0 comments on commit c8ba043

Please sign in to comment.