Current section
Files
Jump to
Current section
Files
lib/graylog_search.ex
defmodule GraylogSearch do
@moduledoc """
Constructs Graylog search URL.
"""
@doc """
Given a base URL, returns a URI for GraylogSearch pipelines.
"""
def new(url) when is_binary(url) do
uri = URI.parse(url)
%URI{uri | path: "/search"}
end
def url(%URI{} = uri), do: URI.to_string(uri)
@doc """
Search for a message by the given query term or phrase.
This function can be chained to combine queries with AND.
By default, all fields are included in the search
when a field to search in is not specified.
"""
@spec by(URI.t(), String.t()) :: URI.t()
def by(%URI{} = uri, query) when is_binary(query) do
sanitised_query = sanitise_input(query)
and_query(uri, sanitised_query)
end
@doc "Alias for `by/2`"
@spec and_by(URI.t(), String.t()) :: URI.t()
def and_by(uri, query), do: by(uri, query)
defp and_query(uri, nil), do: uri
defp and_query(%URI{query: nil} = uri, query) do
query_string = URI.encode_query(%{"q" => query})
%URI{uri | query: query_string}
end
defp and_query(%URI{} = uri, query) do
query_string =
uri.query
|> URI.decode_query()
|> Map.get_and_update("q", &add_and_query(&1, query))
|> (fn {_old_query, new_query} -> new_query end).()
|> URI.encode_query()
%URI{uri | query: query_string}
end
@doc """
Search messages by another term or phrase.
Uses the OR operator to combine queries.
"""
@spec or_by(URI.t(), String.t()) :: URI.t()
def or_by(%URI{} = uri, query) when is_binary(query) do
sanitised_query = sanitise_input(query)
or_query(uri, sanitised_query)
end
defp or_query(uri, nil), do: uri
defp or_query(%URI{query: nil} = uri, _query), do: uri
defp or_query(%URI{} = uri, query) do
query_string =
uri.query
|> URI.decode_query()
|> Map.get_and_update("q", &add_or_query(&1, query))
|> (fn {_old_query, new_query} -> new_query end).()
|> URI.encode_query()
%URI{uri | query: query_string}
end
@doc """
Search for messages that do not include a term or phrase.
Uses the NOT operator. Can be chained to combine queries with AND NOT.
"""
@spec not_by(URI.t(), String.t()) :: URI.t()
def not_by(%URI{} = uri, query) when is_binary(query) do
sanitised_query = sanitise_input(query)
not_query(uri, sanitised_query)
end
defp not_query(uri, nil), do: uri
defp not_query(%URI{query: nil} = uri, query) do
query_string = URI.encode_query(%{"q" => "NOT #{query}"})
%URI{uri | query: query_string}
end
defp not_query(%URI{} = uri, query) do
query_string =
uri.query
|> URI.decode_query()
|> Map.get_and_update("q", &add_not_query(&1, query))
|> (fn {_old_query, new_query} -> new_query end).()
|> URI.encode_query()
%URI{uri | query: query_string}
end
@doc "Alias for `not_by/2`"
def and_not(uri, query), do: not_by(uri, query)
defp add_and_query(existing_query, query_addition),
do: add_to_query(existing_query, query_addition, " AND ")
defp add_or_query(existing_query, query_addition),
do: add_to_query(existing_query, query_addition, " OR ")
defp add_not_query(existing_query, query_addition),
do: add_to_query(existing_query, query_addition, " AND NOT ")
defp add_to_query(existing_query, query_addition, delimiter) do
new_query = existing_query <> delimiter <> query_addition
{existing_query, new_query}
end
defp sanitise_input(query) when is_binary(query) do
case String.trim(query) do
"" -> nil
query -> query
end
end
end