defmt2log 0.1.1

Adapt full defmt logging to ordinary log records
Documentation
# `defmt2log`

Keep writing real `defmt` in code that also runs on the host.

`defmt2log` lets a host binary decode those `defmt` frames and emit ordinary
[`log`](https://docs.rs/log) records, so you keep:

- full `defmt` format hints and syntax in the code
- `DEFMT_LOG` compile-time filtering
- normal host `log` tooling such as `RUST_LOG`, `env_logger`, and downstream
  `log` sinks

Initialization modes:

- `init_from_current_exe()` for the normal host-binary case
- `init_from_elf_path(path)` for any ELF path with a merged `.defmt` section,
  and also for the current executable
- `init_from_merged_elf_bytes(bytes)` for pre-merged ELF bytes

## Usage

```rust
fn main() {
  env_logger::init();
  defmt2log::init_from_current_exe().unwrap();
  defmt::info!("word {=u32:#010x}", 0x1234u32);  
}
```

- normal debug and release host binaries work as well as libtest unit
  tests, examples, and integration tests; they need `defmt2log::init_from_*()`
- rustdoc doctest executables are worse: the bundled doctest rlib still
  contains `.defmt.info.*`, but the final `rust_out` test executable keeps only
  `.defmt.end` plus `_defmt_version_` / `_defmt_encoding_`, so there is no
  table to decode at runtime; those split metadata sections are dead-stripped
  from the final doctest executable

Recommended default:

- build with `DEFMT_LOG=info`
- run with `RUST_LOG=info`
- leave `log` compile-time max-level features alone
- source locations are loaded on a best-effort basis; if they cannot be loaded,
  decoding still works and `defmt2log` warns once
- if `DEFMT_LOG` is unset or more restrictive than your callsites, normal
  `defmt::{trace,debug,info,warn,error}!` output is compiled out entirely; in
  that case `defmt2log` may still initialize successfully, but there is
  nothing for it to decode
- `DEFMT_LOG=off` and no `defmt::println!()` removes the need for a `defmt` `#[global_logger]`

## Filters

- `DEFMT_LOG` is the compile-time filter for `defmt`
- `RUST_LOG` is the runtime filter for the host `log` sink
- `max_level_*` and `release_max_level_*` affect ordinary host `log` callsites,
  not `defmt`

The important consequence is simple: `RUST_LOG` cannot bring back `defmt`
callsites that `DEFMT_LOG` compiled out.

Note that `defmt::println!()` is converted into `INFO` log level messages.

## Avoid

- `DEFMT_LOG=trace` with `RUST_LOG=warn` unless you intentionally want to pay
  decode cost for logs the sink will hide
- using `max_level_*` features to control `defmt`
- using `init_from_merged_elf_bytes()` for a normal host executable; that API
  is only for ELFs that already contain a merged `.defmt` section.
- expecting `init_from_elf_path(path)` to synthesize a table for an arbitrary
  non-running host binary without a merged `.defmt` section

## Limitations

- no doctests yet
- `defmt2log` typically less efficient than pure `log`; the overhead is
  the sum of the defmt overheads: serialization, deserialization, and formatting
- every compile-time-enabled `defmt` frame is decoded in-process
- `init_from_current_exe()` is Linux-oriented today:
  the split-`.defmt.*` synthetic fallback depends on `/proc/self/maps`
- `init_from_elf_path()` and `init_from_merged_elf_bytes()` are the more
  portable modes: they work when the input already has a merged `.defmt`
  section
- native macOS current-executable support is not a supported path today
- host bitflags names require linker support that preserves `.defmt.end*`
  metadata; without that, host decoders only see the bitflags format tag and
  fall back to the raw numeric value
- a future host-side linker setup may preserve `.defmt.end*` and merge
  `.defmt.*` into one real `.defmt` section so `defmt-decoder::Table::parse()`
  can be used directly, but that is not a supported recipe yet
- With the synthesized table, the naive unmerged `DefmtSymbol::runtime_index: u16`
  can collide

## Alternatives

- only `log::*`: simplest host setup, but you give up efficient `defmt` format
  hints and `DEFMT_LOG` compile-time filtering.
- `defmt-or-log` or the `fmt.rs` trick: useful when one shared codebase must
  compile against either backend, but the shared callsites have to stay within
  the portable subset.
- `defmt-logger`: also aims at `defmt` -> `log` but it is old. `defmt2log` is built
  around current `defmt-decoder` `log` interop and preserves the normal host
  `log` pipeline end to end: `RUST_LOG` filtering, existing sinks, and other
  downstream `log` machinery.
- external decoding such as `defmt-print`: keeps full `defmt`, but moves the
  decode and process orchestration outside the program. `defmt2log` keeps the
  same logging stream inside the host process, merges with other `log` sources,
  and feeds ordinary `log` sinks directly.