Skip to content

Instantly share code, notes, and snippets.

@kylethebaker
Created September 16, 2017 00:08
Show Gist options
  • Save kylethebaker/9edf584828c227f3f957f8086a73a8a6 to your computer and use it in GitHub Desktop.
Save kylethebaker/9edf584828c227f3f957f8086a73a8a6 to your computer and use it in GitHub Desktop.
Example polling a log file
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Log Reader - polls log file and sends new lines to channel
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
defmodule LogReader do
use GenServer
@log_file "priv/some_log.log"
@poll_interval 5 * 1000 # 5 seconds
def run_test() do
{:ok, _} = LogWriter.start_link()
{:ok, _} = LogReader.start_link()
end
def start_link(_ \\ []) do
GenServer.start_link(__MODULE__, :ok, name: LogReader)
end
def init(:ok) do
# open the log file and set the pointer to the end so that we only grab
# new log messages
{:ok, fp} = File.open(@log_file, [:read])
:file.position(fp, :eof)
poll()
{:ok, fp}
end
def handle_info(:read_log_lines, fp) do
# consume any new log lines and pass them off the channel
fp |> read_til_eof |> send_to_channel
poll()
{:noreply, fp}
end
def read_til_eof(fp),
do: read_til_eof(IO.binread(fp, :line), fp, [])
def read_til_eof(:eof, _fp, buffer), do: buffer
def read_til_eof(line, fp, buffer),
do: read_til_eof(IO.binread(fp, :line), fp, buffer ++ [line])
# this could be handing off the new lines to some service or sending directly
# to the channel or whatever
def send_to_channel([]), do: :ok
def send_to_channel(lines),
do: for line <- lines, do: IO.puts line
defp poll(),
do: Process.send_after(self(), :read_log_lines, @poll_interval)
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Log Writer - simulates log writes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
defmodule LogWriter do
use GenServer
@log_file "priv/some_log.log"
def start_link(_ \\ []) do
GenServer.start_link(__MODULE__, :ok, name: LogWriter)
end
def init(:ok) do
{:ok, fp} = File.open(@log_file, [:append])
poll()
{:ok, fp}
end
def handle_info(:write_log, fp) do
for _ <- 0..:rand.uniform(5), do: IO.puts fp, make_log_message()
poll()
{:noreply, fp}
end
def make_log_message() do
time = :os.system_time(:milli_seconds) |> to_string()
body = :crypto.strong_rand_bytes(15) |> Base.url_encode64
"[#{time}] #{body}"
end
defp poll() do
interval = :rand.uniform(10) * 1000
Process.send_after(self(), :write_log, interval)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment