# spdlog Source Location Tracking: A Complete Guide to __FILE__, __LINE__, and Function Names

> Unlock powerful spdlog source location tracking with __LINE__, __FILE__, and __func__. Learn how to capture and format detailed debug information for your C++ applications.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: deep-dive
- Published: 2026-07-12

---

**spdlog automatically captures source file paths, line numbers, and function names using the `__FILE__`, `__LINE__`, and `__func__` macros, storing them in a lightweight `source_loc` struct that pattern formatters can render with `%s` or `%#` flags.**

The **spdlog** logging library provides built-in **source location tracking** that attaches debugging metadata to every log entry without manual instrumentation. This feature leverages C++ preprocessor macros and optional C++20 `std::source_location` support to pinpoint exactly where each message originates in your codebase.

## The source_loc Data Structure

At the heart of spdlog's location tracking is the **`source_loc`** struct defined in [`include/spdlog/common.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/common.h). This lightweight constexpr-capable container stores three essential pointers:

```cpp
struct source_loc {
    constexpr source_loc() = default;
    constexpr source_loc(const char *filename_in, int line_in, const char *funcname_in)
        : filename{filename_in}, line{line_in}, funcname{funcname_in} {}
    constexpr bool empty() const noexcept { return line <= 0; }
    const char *filename{nullptr};
    int line{0};
    const char *funcname{nullptr};
};

```

The `empty()` method allows the library to detect when source tracking is disabled or unavailable, ensuring formatters skip rendering location data rather than printing null pointers.

## How Macros Inject Source Locations

The library automatically injects location data through the **`SPDLOG_LOGGER_CALL`** macro found in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h). When you call `spdlog::info()` or `SPDLOG_INFO()`, the macro expands to pass a `source_loc` instance constructed from the current translation unit's `__FILE__`, `__LINE__`, and `SPDLOG_FUNCTION` (which maps to `__func__` or `__FUNCTION__` depending on your compiler):

```cpp
#define SPDLOG_LOGGER_CALL(logger, level, ...) \
    (logger)->log(SPDLOG_NAMESPACE::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)

```

This macro feeds into the **logger** class's overloaded `log()` methods in [`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h), specifically the variants accepting a `source_loc` parameter. The location data ultimately resides in the `log_msg` structure's `source` member before reaching sinks and formatters.

## Pattern Formatters for Source Output

Once captured, location data is rendered through specialized formatter classes in [`include/spdlog/pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter-inl.h). You control the output format using specific pattern flags:

- **`%s`** – Renders the full location via `source_location_formatter` (format: `filename:line:funcname`)
- **`%#`** – Displays filename and line only via the same formatter (format: `filename:line`)
- **`%t`** – Filename only via `source_filename_formatter`
- **Additional flags** – Line numbers (`%#`) and function names (`%!`) via `source_linenum_formatter` and `source_funcname_formatter` respectively

Formatters check `msg.source.empty()` before writing, ensuring clean output when tracking is disabled.

## Practical Usage Examples

### Basic Logging with Automatic Location

Simply use standard logging macros; the location attaches automatically:

```cpp
#include <spdlog/spdlog.h>

int main() {
    spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %s:%# %v");

    spdlog::info("Application started");
    spdlog::error("Failed to open {}", "config.txt");
}

```

Output:

```

[2026-07-12 14:23:41.123] [info] main.cpp:5 Application started
[2026-07-12 14:23:41.124] [error] main.cpp:6 Failed to open config.txt

```

### Displaying Only Filename and Line

Use the `%#` flag to omit function names and print concise file:line references:

```cpp
spdlog::set_pattern("[%l] %s:%# %v");

```

### C++20 std::source_location Support

If your compiler supports C++20, spdlog accepts `std::source_location` directly, converting it internally to `source_loc`:

```cpp
#include <spdlog/spdlog.h>
#include <source_location>

void log_with_loc(const std::source_location& loc = std::source_location::current()) {
    spdlog::log(loc, spdlog::level::info, "Message from helper");
}

int main() {
    log_with_loc();  // Prints the call site location, not the helper's location
}

```

### Zero-Cost Disable

Define **`SPDLOG_DISABLE_SOURCE_LOC`** before including headers to eliminate all runtime overhead. Macros then pass an empty `source_loc{}`, and pattern formatters render nothing for location flags:

```cpp
#define SPDLOG_DISABLE_SOURCE_LOC
#include <spdlog/spdlog.h>

```

## System-Specific Integration

Certain sinks utilize location data beyond text formatting. The **`systemd_sink`** in [`include/spdlog/sinks/systemd_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/systemd_sink.h) extracts `msg.source` to populate structured journal fields (`CODE_FILE`, `CODE_LINE`, `CODE_FUNC`), enabling precise filtering in systemd journal viewers.

## Summary

- **Location storage**: The `source_loc` struct in [`include/spdlog/common.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/common.h) holds `filename`, `line`, and `funcname` as `const char*` and `int`.
- **Automatic injection**: The `SPDLOG_LOGGER_CALL` macro in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) passes `__FILE__`, `__LINE__`, and `SPDLOG_FUNCTION` to `logger::log()` overloads.
- **Pattern control**: Use `%s` for full location, `%#` for file:line, or specific flags like `%t` for filename only in [`include/spdlog/pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter-inl.h).
- **C++20 support**: Pass `std::source_location::current()` directly to logging functions.
- **Zero-cost opt-out**: Define `SPDLOG_DISABLE_SOURCE_LOC` to compile out all location tracking overhead.

## Frequently Asked Questions

### How do I show the function name in spdlog output?

Use the **`%s`** pattern flag in your formatter, which renders `filename:line:funcname`. Alternatively, use **`%!`** for just the function name. The `source_funcname_formatter` class in [`include/spdlog/pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter-inl.h) handles this specific conversion.

### Can I use spdlog source location tracking without macros?

Yes. When using C++20, you can pass `std::source_location::current()` directly to `spdlog::log()` or logger methods. The library converts this to its internal `source_loc` type automatically, bypassing the macro layer while maintaining the same metadata.

### What is the performance cost of source location tracking?

When enabled, the cost is minimal—only three pointer/size_t copies per log entry. However, you can eliminate all overhead by defining **`SPDLOG_DISABLE_SOURCE_LOC`** before including headers. This causes macros to pass empty `source_loc{}` instances, making the feature zero-cost at runtime.

### Why does my output show nothing for %s or %# flags?

This occurs when source location tracking is disabled via `SPDLOG_DISABLE_SOURCE_LOC`, or when using logging methods that bypass the macros (like direct `logger->log()` calls without passing a `source_loc`). Ensure you use the standard `SPDLOG_INFO`, `spdlog::info()`, or equivalent macro-based calls to populate the location data.