RSS Git Download  Clone
Raw Blame History
Here's a **complete, final summary** of the working setup for
**Log::Any → Dancer2 logging** with correct caller info, moved into its own package.

---

## Goal

* Use `Log::Any` inside model classes (`$log->debug(...)`).
* Forward those messages into the **current Dancer2 logger** (file/console/whatever).
* Preserve the **real file and line** of the model call.
* Keep all adapter setup in a separate package.

---

## 1️⃣ Logging Setup Package

`lib/MyApp/LogSetup.pm`

```perl
package MyApp::LogSetup;
use strict;
use warnings;

use Dancer2 ();          # load but don’t import the DSL
use Log::Any::Adapter;

sub init {
    Log::Any::Adapter->set(
        Capture =>
            min_level => 'debug',
            to        => sub {
                my ($method, $self, $format, @params) = @_;
                my $msg = @params ? sprintf($format, @params) : $format;

                # Find the first registered Dancer2 app
                my ($app) = @{ Dancer2->runner->apps } or return;

                # Skip Log::Any frames so caller points to your model code
                my (undef, $file, $line) = caller(3);

                $app->logger_engine->log(
                    $method => $msg,
                    caller  => [$file, $line],
                );
            },
    );
}

1;
```

* `Dancer2->runner->apps` returns all running apps; we use the first for a single-app setup.
* `caller(3)` skips the adapter + Log::Any wrappers so the model’s file/line is recorded.

---

## 2️⃣ Main Application

`lib/MyApp.pm`

```perl
package MyApp;
use Dancer2;
use MyApp::LogSetup;

# Initialise Log::Any forwarding before routes
MyApp::LogSetup::init();

get '/' => sub { "Hello World" };

1;
```

Configure `config.yml` normally, e.g.:

```yaml
logger: "file"
log: "debug"
engines:
  logger:
    file:
      filename: "/var/log/myapp.log"
      layout: "%m in %f line %l"
```

`%f` and `%l` will show the model file/line we supply.

---

## 3️⃣ Model Classes

`lib/MyApp/Model/User.pm`

```perl
package MyApp::Model::User;
use strict;
use warnings;
use Log::Any '$log';

sub create {
    $log->debug("Creating a user");  # will log with this file/line
    ...
}
1;
```

No Dancer2 dependency here — only `Log::Any`.

---

## 4️⃣ Behaviour

* Any `$log->debug/info/warning/...` inside models is captured by the callback.
* Messages are forwarded to the Dancer2 logger (File, Console, Syslog, etc.) exactly like native `debug`.
* Log entries display the **model’s actual file and line number**, not the adapter.

---

### Notes & Tips

* If you run **multiple Dancer2 apps** in one process, filter `Dancer2->runner->apps` by app name.
* In unit tests, you can skip `MyApp::LogSetup::init()` and instead set
  `Log::Any::Adapter->set('Test')` to capture logs without Dancer2.
* Adjust `caller(3)` if you add extra wrapper layers.

---

This pattern keeps **models clean**, gives you **centralised logging setup**, and ensures all Log::Any messages appear in **Dancer2’s normal logs with correct origin information**.