summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rabbit_log_tail.erl53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/rabbit_log_tail.erl b/src/rabbit_log_tail.erl
new file mode 100644
index 0000000000..d5764c90b9
--- /dev/null
+++ b/src/rabbit_log_tail.erl
@@ -0,0 +1,53 @@
+-module(rabbit_log_tail).
+
+-export([tail_n_lines/2]).
+% -export([init_tail_stream/2, tail_send/2, tail_receive/2]).
+
+-define(GUESS_OFFSET, 200).
+
+tail_n_lines(Filename, N) ->
+ case file:open(Filename, [read, binary]) of
+ {ok, File} ->
+ {ok, Eof} = file:position(File, eof),
+ %% Eof may move. Only read up to the current one.
+ Result = reverse_read_n_lines(N, N, File, Eof, Eof),
+ file:close(File),
+ Result;
+ Error -> Error
+ end.
+
+reverse_read_n_lines(N, OffsetN, File, Position, Eof) ->
+ GuessPosition = offset(Position, OffsetN),
+ case read_lines_from_position(File, GuessPosition, Eof) of
+ {ok, Lines} ->
+ NLines = length(Lines),
+ case {NLines >= N, GuessPosition == 0} of
+ %% Take only N lines if there is more
+ {true, _} -> lists:nthtail(NLines - N, Lines);
+ %% Safe to assume that NLines is less then N
+ {_, true} -> Lines;
+ %% Adjust position
+ _ ->
+ reverse_read_n_lines(N, N - NLines + 1, File, GuessPosition, Eof)
+ end;
+ Error -> Error
+ end.
+
+read_from_position(File, GuessPosition, Eof) ->
+ file:pread(File, GuessPosition, max(0, Eof - GuessPosition)).
+
+read_lines_from_position(File, GuessPosition, Eof) ->
+ case read_from_position(File, GuessPosition, Eof) of
+ {ok, Data} -> {ok, crop_lines(Data)};
+ Error -> Error
+ end.
+
+crop_lines(Data) ->
+ %% Drop the first line, because it's most likely partial.
+ case binary:split(Data, <<"\n">>, [global, trim]) of
+ [_|Rest] -> Rest;
+ [] -> []
+ end.
+
+offset(Base, N) ->
+ max(0, Base - N * ?GUESS_OFFSET). \ No newline at end of file