Packages

LogDot SDK for Elixir - Cloud logging and metrics

Current section

Files

Jump to
logdot lib logdot.ex
Raw

lib/logdot.ex

defmodule LogDot do
@moduledoc """
LogDot SDK for Elixir - Cloud logging and metrics.
## Configuration
config :logdot,
api_key: "ilog_live_YOUR_API_KEY",
hostname: "my-app",
entity_name: "my-service",
entity_description: "My Service Description",
timeout: 5000,
retry_attempts: 3,
debug: false
## Usage
# Logging
LogDot.info("User logged in", %{user_id: 123})
LogDot.error("Database connection failed", %{host: "db.example.com"})
# Context-aware logging
logger = LogDot.with_context(%{user_id: 123, request_id: "abc"})
LogDot.info(logger, "User action") # Includes user_id and request_id
# Metrics
LogDot.init_metrics()
LogDot.metric("response_time", 123.45, "ms", %{endpoint: "/api/users"})
# Batch logging
LogDot.begin_batch()
LogDot.info("Message 1")
LogDot.info("Message 2")
LogDot.send_batch()
"""
@type log_level :: :debug | :info | :warn | :error
@type tags :: map()
@type metadata :: map()
# Context struct for context-aware logging
defmodule Context do
@moduledoc """
A context struct for context-aware logging.
Create a context with `LogDot.with_context/1` and use it with logging functions.
"""
defstruct context: %{}
@type t :: %__MODULE__{context: map()}
end
@doc """
Create a new context logger with the given context map.
The context will be merged with any tags provided to log functions.
## Example
logger = LogDot.with_context(%{user_id: 123, request_id: "abc-123"})
LogDot.info(logger, "Processing request") # Includes user_id and request_id
# Chain contexts
detailed = LogDot.with_context(logger, %{operation: "checkout"})
LogDot.info(detailed, "Starting checkout") # Includes all three fields
"""
@spec with_context(map()) :: Context.t()
def with_context(context) when is_map(context) do
%Context{context: context}
end
@doc """
Create a new context logger by merging additional context into an existing context.
"""
@spec with_context(Context.t(), map()) :: Context.t()
def with_context(%Context{context: existing}, new_context) when is_map(new_context) do
%Context{context: Map.merge(existing, new_context)}
end
@doc """
Get the context map from a context logger.
"""
@spec get_context(Context.t()) :: map()
def get_context(%Context{context: context}), do: context
# Helper to merge context with tags
defp merge_tags(%Context{context: context}, tags) do
Map.merge(context, tags)
end
defp merge_tags(nil, tags), do: tags
# Logging functions
@doc """
Send a debug level log.
"""
@spec debug(String.t(), tags()) :: :ok | {:error, term()}
def debug(message), do: debug(message, %{})
def debug(%Context{} = ctx, message), do: debug(ctx, message, %{})
def debug(message, tags) when is_binary(message), do: LogDot.Logger.debug(message, tags)
@doc """
Send a debug level log with context.
"""
@spec debug(Context.t(), String.t(), tags()) :: :ok | {:error, term()}
def debug(%Context{} = ctx, message, tags) do
LogDot.Logger.debug(message, merge_tags(ctx, tags))
end
@doc """
Send an info level log.
"""
@spec info(String.t(), tags()) :: :ok | {:error, term()}
def info(message), do: info(message, %{})
def info(%Context{} = ctx, message), do: info(ctx, message, %{})
def info(message, tags) when is_binary(message), do: LogDot.Logger.info(message, tags)
@doc """
Send an info level log with context.
"""
@spec info(Context.t(), String.t(), tags()) :: :ok | {:error, term()}
def info(%Context{} = ctx, message, tags) do
LogDot.Logger.info(message, merge_tags(ctx, tags))
end
@doc """
Send a warning level log.
"""
@spec warn(String.t(), tags()) :: :ok | {:error, term()}
def warn(message), do: warn(message, %{})
def warn(%Context{} = ctx, message), do: warn(ctx, message, %{})
def warn(message, tags) when is_binary(message), do: LogDot.Logger.warn(message, tags)
@doc """
Send a warning level log with context.
"""
@spec warn(Context.t(), String.t(), tags()) :: :ok | {:error, term()}
def warn(%Context{} = ctx, message, tags) do
LogDot.Logger.warn(message, merge_tags(ctx, tags))
end
@doc """
Send an error level log.
"""
@spec error(String.t(), tags()) :: :ok | {:error, term()}
def error(message), do: error(message, %{})
def error(%Context{} = ctx, message), do: error(ctx, message, %{})
def error(message, tags) when is_binary(message), do: LogDot.Logger.error(message, tags)
@doc """
Send an error level log with context.
"""
@spec error(Context.t(), String.t(), tags()) :: :ok | {:error, term()}
def error(%Context{} = ctx, message, tags) do
LogDot.Logger.error(message, merge_tags(ctx, tags))
end
@doc """
Send a log at the specified level.
"""
@spec log(log_level(), String.t(), tags()) :: :ok | {:error, term()}
def log(level, message), do: log(level, message, %{})
def log(%Context{} = ctx, level, message), do: log(ctx, level, message, %{})
def log(level, message, tags) when is_atom(level) and is_binary(message), do: LogDot.Logger.log(level, message, tags)
@doc """
Send a log at the specified level with context.
"""
@spec log(Context.t(), log_level(), String.t(), tags()) :: :ok | {:error, term()}
def log(%Context{} = ctx, level, message, tags) do
LogDot.Logger.log(level, message, merge_tags(ctx, tags))
end
# Batch operations for logging
@doc """
Begin batch mode for logs.
"""
@spec begin_batch() :: :ok
def begin_batch, do: LogDot.Logger.begin_batch()
@doc """
Send all queued logs in batch mode.
"""
@spec send_batch() :: :ok | {:error, term()}
def send_batch, do: LogDot.Logger.send_batch()
@doc """
End batch mode for logs.
"""
@spec end_batch() :: :ok
def end_batch, do: LogDot.Logger.end_batch()
@doc """
Clear the log batch queue.
"""
@spec clear_batch() :: :ok
def clear_batch, do: LogDot.Logger.clear_batch()
@doc """
Get the current log batch size.
"""
@spec batch_size() :: non_neg_integer()
def batch_size, do: LogDot.Logger.batch_size()
# Metrics functions
@doc """
Initialize the metrics entity.
"""
@spec init_metrics(metadata()) :: :ok | {:error, term()}
def init_metrics(metadata \\ %{}), do: LogDot.Metrics.init_entity(metadata)
@doc """
Send a single metric.
"""
@spec metric(String.t(), number(), String.t(), tags()) :: :ok | {:error, term()}
def metric(name, value, unit, tags \\ %{}) do
LogDot.Metrics.send(name, value, unit, tags)
end
@doc """
Begin batch mode for a single metric type.
"""
@spec begin_metric_batch(String.t(), String.t()) :: :ok
def begin_metric_batch(name, unit), do: LogDot.Metrics.begin_batch(name, unit)
@doc """
Add a value to the current metric batch.
"""
@spec add_metric(number(), tags()) :: :ok | {:error, term()}
def add_metric(value, tags \\ %{}), do: LogDot.Metrics.add(value, tags)
@doc """
Begin multi-metric batch mode.
"""
@spec begin_multi_batch() :: :ok
def begin_multi_batch, do: LogDot.Metrics.begin_multi_batch()
@doc """
Add a metric to the multi-metric batch.
"""
@spec add_multi_metric(String.t(), number(), String.t(), tags()) :: :ok | {:error, term()}
def add_multi_metric(name, value, unit, tags \\ %{}) do
LogDot.Metrics.add_metric(name, value, unit, tags)
end
@doc """
Send all queued metrics.
"""
@spec send_metric_batch() :: :ok | {:error, term()}
def send_metric_batch, do: LogDot.Metrics.send_batch()
@doc """
End metric batch mode.
"""
@spec end_metric_batch() :: :ok
def end_metric_batch, do: LogDot.Metrics.end_batch()
@doc """
Get the current metric batch size.
"""
@spec metric_batch_size() :: non_neg_integer()
def metric_batch_size, do: LogDot.Metrics.batch_size()
@doc """
Get the entity ID.
"""
@spec entity_id() :: String.t() | nil
def entity_id, do: LogDot.Metrics.entity_id()
@doc """
Check if metrics are initialized.
"""
@spec metrics_ready?() :: boolean()
def metrics_ready?, do: LogDot.Metrics.is_ready?()
end