LogDot SDK for Elixir

Cloud logging and metrics made simple

Hex.pm versionHex.pm downloadsMIT LicenseElixir 1.14+OTP 25+

WebsiteDocumentationQuick StartAPI Reference


Features

Installation

Add logdot to your dependencies in mix.exs:

def deps do
  [
    {:logdot, "~> 1.0"}
  ]
end

Configuration

# config/config.exs
config :logdot,
  api_key: "ilog_live_YOUR_API_KEY",
  hostname: "my-app",
  timeout: 5000,
  retry_attempts: 3,
  debug: false

Quick Start

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# LOGGING
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
LogDot.info("Application started", %{version: "1.0.0"})
LogDot.error("Something went wrong", %{error_code: 500})

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# METRICS
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Create or find an entity first
{:ok, entity} = LogDot.Metrics.get_or_create_entity(
  "my-service",
  "My production service",
  %{environment: "production"}
)

# Bind to the entity for sending metrics
:ok = LogDot.Metrics.for_entity(entity.id)

# Now send metrics
LogDot.metric("response_time", 123.45, "ms", %{endpoint: "/api/users"})

Logging

Log Levels

LogDot.debug("Debug message")
LogDot.info("Info message")
LogDot.warn("Warning message")
LogDot.error("Error message")

Structured Tags

LogDot.info("User logged in", %{
  user_id: 12345,
  ip_address: "192.168.1.1",
  session_id: "abc123"
})

Context-Aware Logging

Create loggers with persistent context that automatically flows through your application:

# Create a context for a specific request
ctx = LogDot.with_context(%{request_id: "abc-123", user_id: 456})

# All logs include request_id and user_id automatically
LogDot.info(ctx, "Processing request", %{})
LogDot.debug(ctx, "Fetching user data", %{})

# Chain contexts — they merge together
detailed_ctx = LogDot.with_context(ctx, %{operation: "checkout"})

# This log has request_id, user_id, AND operation
LogDot.info(detailed_ctx, "Starting checkout process", %{})

Batch Logging

Send multiple logs in a single HTTP request:

LogDot.begin_batch()

LogDot.info("Step 1 complete")
LogDot.info("Step 2 complete")
LogDot.info("Step 3 complete")

LogDot.send_batch()  # Single HTTP request
LogDot.end_batch()

Metrics

Entity Management

# Create a new entity
{:ok, entity} = LogDot.Metrics.create_entity(
  "my-service",
  "Production API server",
  %{environment: "production", region: "us-east-1"}
)

# Find existing entity
{:ok, existing} = LogDot.Metrics.get_entity_by_name("my-service")

# Get or create (recommended)
{:ok, entity} = LogDot.Metrics.get_or_create_entity(
  "my-service",
  "Created if not exists"
)

Sending Metrics

:ok = LogDot.Metrics.for_entity(entity.id)

# Single metric
LogDot.metric("cpu_usage", 45.2, "percent")
LogDot.metric("response_time", 123.45, "ms", %{
  endpoint: "/api/users",
  method: "GET"
})

Batch Metrics

# Same metric, multiple values
LogDot.begin_metric_batch("temperature", "celsius")
LogDot.add_metric(23.5, %{sensor: "room1"})
LogDot.add_metric(24.1, %{sensor: "room2"})
LogDot.add_metric(23.8, %{sensor: "room3"})
LogDot.send_metric_batch()
LogDot.end_metric_batch()

# Multiple different metrics
LogDot.begin_multi_batch()
LogDot.add_multi_metric("cpu", 45.5, "percent")
LogDot.add_multi_metric("memory", 8192, "MB")
LogDot.add_multi_metric("disk", 75.0, "percent")
LogDot.send_metric_batch()
LogDot.end_metric_batch()

Auto-Instrumentation (Phoenix)

Automatically capture Phoenix HTTP requests, errors, and Ecto database queries using the built-in :telemetry system. No additional dependencies required.

Setup

In your application.ex:

def start(_type, _args) do
  # Initialize metrics entity (required for duration metrics)
  LogDot.init_metrics()

  LogDot.Phoenix.attach(
    ecto_prefixes: [[:my_app, :repo]]
  )

  children = [
    # ... your supervision tree
  ]

  Supervisor.start_link(children, strategy: :one_for_one)
end

What Gets Captured

Options

Option Type Default Description
:endpoint boolean true Log Phoenix HTTP requests
:errors boolean true Log Phoenix errors
:ecto boolean true Log Ecto database queries
:metrics boolean true Send duration metrics
:ignore_paths list [] Paths to skip (e.g. ["/health"])
:ecto_prefixes list [] Ecto telemetry prefixes for your repos
:capture_logging boolean false Forward Elixir Logger calls to LogDot

Detaching

LogDot.Phoenix.detach()

Log Capture

Automatically forward Elixir Logger calls to LogDot. The original Logger behavior is preserved — messages still appear in your console and file backends as usual.

This works in any Elixir/OTP application (Plug, Bandit, standalone GenServers, Mix tasks, etc.), not just Phoenix. If you use LogDot.Phoenix.attach(capture_logging: true), the handler is installed automatically — don't also call LogDot.capture_logging() or it will return {:error, ...} since the handler is already registered.

Standalone Usage

# Start capturing
LogDot.capture_logging()

# All Logger calls are now sent to LogDot
require Logger
Logger.info("This goes to LogDot")          # severity: info
Logger.error("Something failed")             # severity: error
Logger.warning("Watch out")                  # severity: warn
Logger.debug("Debug details")                # severity: debug

# Stop capturing
LogDot.stop_capture_logging()

With Phoenix

When using Phoenix auto-instrumentation, pass capture_logging: true:

# application.ex
def start(_type, _args) do
  LogDot.Phoenix.attach(
    capture_logging: true,
    ecto_prefixes: [[:my_app, :repo]]
  )

  children = [...]
  Supervisor.start_link(children, strategy: :one_for_one)
end

How It Works

LogDot.LoggerBackend is an Erlang :logger handler:

  1. Installed via :logger.add_handler/3 (OTP 21+ logging system)
  2. Receives all log events from the BEAM — Logger.info/1, Logger.error/1, IO.puts/1 (when :console backend is not the only handler), etc.
  3. Formats the message (supports :string, :report, and :io_lib.format message formats)
  4. Maps the Erlang/Elixir log level to a LogDot severity
  5. Sends via LogDot.log/3 (the existing GenServer-backed API)
  6. A process dictionary guard (Process.get(:logdot_sending)) prevents infinite loops — when LogDot's own HTTP client triggers Logger events during delivery, those events are silently skipped
  7. Messages longer than 16KB are truncated
  8. All errors are rescued — a crashed :telemetry handler gets permanently detached, but a crashed :logger handler can also cause issues, so defensive coding is essential

Level Mapping

Erlang/Elixir Level LogDot Severity
:emergencyerror
:alerterror
:criticalerror
:errorerror
:warningwarn
:warnwarn
:noticeinfo
:infoinfo
:debugdebug

Tags

All captured Logger logs include { source: "elixir_logger" } in their tags, so you can filter them from manually sent logs in the LogDot dashboard.

Manual Handler Management

For advanced usage, you can manage the handler directly:

# Add handler manually
:logger.add_handler(:logdot_backend, LogDot.LoggerBackend, %{})

# Remove handler manually
:logger.remove_handler(:logdot_backend)

API Reference

LogDot (Main Module)

Function Description
with_context(context) Create a context struct
with_context(ctx, context) Chain contexts together
get_context(ctx) Get context map
debug/info/warn/error(message, tags \\ %{}) Send log at level
debug/info/warn/error(ctx, message, tags) Send log with context
begin_batch() Start batch mode
send_batch() Send queued logs
end_batch() End batch mode
clear_batch() Clear queue without sending
capture_logging() Start forwarding Logger calls to LogDot
stop_capture_logging() Stop forwarding Logger calls

LogDot.Metrics

Function Description
create_entity(name, description, metadata) Create new entity
get_entity_by_name(name) Find entity by name
get_or_create_entity(name, description, metadata) Get or create entity
for_entity(entity_id) Bind to entity for metrics

Requirements

Examples

Create a .env file in the repo root with your API key:

LOGDOT_API_KEY=ilog_live_YOUR_API_KEY

Core SDK test app

Tests logging, metrics, context, and batch operations:

cd elixir
mix run --no-start examples/test_app.exs

Hooks test app (Phoenix + Logger Backend)

Tests Phoenix telemetry handlers and logger backend capture:

cd elixir
mix run --no-start examples/test_hooks.exs

License

MIT License — see LICENSE for details.


logdot.io • Built with care for developers