Current section
Files
Jump to
Current section
Files
lib/hexoku/api/log_session.ex
defmodule Hexoku.API.LogSession do
alias Hexoku.Request
@moduledoc """
A log session is a reference to the http based log stream for an app.
## Attributes
<dl>
<dt>id</dt> <dd>unique identifier of item generated by Heroku</dd>
<dt>logplex_url</dt> <dd>URL for log streaming session</dd>
<dt>created_at</dt> <dd>when item was created</dd>
<dt>updated_at</dt> <dd>when item was last modified</dd>
</dl>
For more info read the [Heroku API Reference](https://devcenter.heroku.com/articles/platform-api-reference#log-session)
"""
@doc """
Create a new log session.
## Payload Attributes
<dl>
<dt>dyno</dt> <dd>dyno to limit results to</dd>
<dt>lines</dt> <dd>number of log lines to stream at once</dd>
<dt>source</dt> <dd>log source to limit results to</dd>
<dt>tail</dt> <dd>whether to stream ongoing logs</dd>
</dl>
## Examples
client |> Hexoku.API.LogSession.create("myapp", %{
source: "app",
lines: 50
})
"""
@spec create(Hexoku.Client.t, binary, Map.t) :: Map.t
def create(client, app, payload), do: Request.post(client, "/apps/#{app}/log-sessions", payload)
@doc """
Helper to get application logs as binary.
## Examples
client |> Hexoku.API.LogSession.get("myapp")
client |> Hexoku.API.LogSession.get("myapp", %{source: "heroku", lines: 10})
"""
@spec get(Hexoku.Client.t, binary, Map.t) :: binary | :error
def get(client, app, options \\ %{}) do
# Bad things might happen if we tail here
options = Dict.drop(options, [:tail, "tail"])
body = Request.post(client, "/apps/#{app}/log-sessions", options)
sender = self()
pid = spawn(fn -> collect_stream(sender, body["logplex_url"]) end)
receive do
{^pid, chunk} -> chunk
after 6000 -> throw {:error, :timeout}
end
end
@doc """
Helper to stream application logs as binary to a fun.
## Examples
client |> Hexoku.API.LogSession.stream("myapp", &(IO.puts(&1)) )
"""
@spec stream(Hexoku.Client.t, binary, Map.t, (binary | :done -> any)) :: :ok
def stream(client, app, options \\ %{}, fun) do
body = Request.post(client, "/apps/#{app}/log-sessions", Dict.put(options, :tail, true))
get_stream(body["logplex_url"], fun)
end
defp collect_stream(sender, url) do
me = self()
get_stream(url, fn (data) -> send(me, data) end)
collect_stream_loop(sender, "")
end
defp collect_stream_loop(sender, acc) do
receive do
:done -> send(sender, {self(), acc})
chunk -> collect_stream_loop(sender, acc<>chunk)
after 5000 -> throw :timeout
end
end
defp get_stream(url, fun) do
pid = spawn(fn -> get_stream_loop(fun) end)
HTTPoison.get(url, [], [stream_to: pid])
pid
end
defp get_stream_loop(fun) do
receive do
%HTTPoison.AsyncEnd{} -> fun.(:done)
%HTTPoison.AsyncChunk{chunk: {:error, {:closed, chunk}}} ->
fun.(chunk)
fun.(:done)
%HTTPoison.AsyncChunk{chunk: {:error, _}} -> fun.(:done)
%HTTPoison.AsyncChunk{chunk: chunk} ->
fun.(chunk)
get_stream_loop(fun)
_ -> get_stream_loop(fun)
end
end
end