README.md

<p align="center">
  <h1 align="center">LogDot SDK for Elixir</h1>
  <p align="center">
    <strong>Cloud logging and metrics made simple</strong>
  </p>
</p>

<p align="center">
  <a href="https://hex.pm/packages/logdot"><img src="https://img.shields.io/hexpm/v/logdot?style=flat-square&color=blue" alt="Hex.pm version"></a>
  <a href="https://hex.pm/packages/logdot"><img src="https://img.shields.io/hexpm/dt/logdot?style=flat-square" alt="Hex.pm downloads"></a>
  <a href="https://github.com/logdot-io/logdot-elixir/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="MIT License"></a>
  <a href="https://elixir-lang.org/"><img src="https://img.shields.io/badge/elixir-%3E%3D1.14-purple?style=flat-square&logo=elixir&logoColor=white" alt="Elixir 1.14+"></a>
  <a href="https://www.erlang.org/"><img src="https://img.shields.io/badge/OTP-%3E%3D25-red?style=flat-square" alt="OTP 25+"></a>
</p>

<p align="center">
  <a href="https://logdot.io">Website</a> •
  <a href="https://docs.logdot.io">Documentation</a> •
  <a href="#quick-start">Quick Start</a> •
  <a href="#api-reference">API Reference</a>
</p>

---

## Features

- **Separate Clients** — Independent Logger and Metrics GenServers for maximum flexibility
- **Context-Aware Logging** — Create loggers with persistent context that automatically flows through your application
- **OTP Compliant** — Built as proper OTP application with supervision tree
- **Entity-Based Metrics** — Create/find entities, then bind to them for organized metric collection
- **Batch Operations** — Efficiently send multiple logs or metrics in a single request
- **Automatic Retry** — Exponential backoff retry with configurable attempts

## Installation

Add `logdot` to your dependencies in `mix.exs`:

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

## Configuration

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

## Quick Start

```elixir
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 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

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

### Structured Tags

```elixir
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:

```elixir
# 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:

```elixir
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

```elixir
# 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

```elixir
: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

```elixir
# 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()
```

## 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 |

### 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

- Elixir 1.14+
- OTP 25+
- [Req](https://hex.pm/packages/req) HTTP client

## License

MIT License — see [LICENSE](LICENSE) for details.

---

<p align="center">
  <a href="https://logdot.io">logdot.io</a> •
  Built with care for developers
</p>