How to log client IP addresses?

So it’s not possible to have this be part of the layout function already?
It has to be within a callback?

I’ll come back with an M(non)WE once I’m back at my machine.

EDIT: This somewhat does it:

from dash import Dash
from dash_bootstrap_components.themes import BOOTSTRAP

from dash import Dash, html, callback, Output, Input
from flask import request

@callback(
    Output('IP', 'children'),
    Input('btn-1', 'n_clicks')
)
def ip(_: int) -> html.Div:
    req: dict = request.__dict__.copy()
    return html.Div(
        children=[
            html.Div(f"{key}: {val}") for key, val in req.items()
        ]
    )

def create_layout(app: Dash) -> html.Div:
    return html.Div(
        className="app-div",  # type: ignore
        children=[
            html.H1(app.title),
            html.Hr(),
            html.Button('Button 1', id='btn-1'),
            html.Div(id="IP"),
        ],
    )

app = Dash(
    __name__,
    suppress_callback_exceptions=True,
    #use_pages=True,
    external_stylesheets=[BOOTSTRAP],
)
app.title = "TEST"
app.layout = create_layout(app)


def main(app: Dash) -> None:
    app.run(debug=True, dev_tools_ui=True, dev_tools_hot_reload=True)


if (__name__ == "__main__"):
    main(app)

However, this requires an option to be present that triggers the callback - a button in this example.
Can this be done without such an option right at call time but not after?
Calling the function in the layout, i.e., html.Div(id="IP", children=ip(0)), breaks the request context (why even? we usually can call functions that generate a layout, can’t we?).

EDIT:
Can a callback have no input? somewhat deals with the same issue which makes it cleaner looking than my button solution:

from typing import Any

@callback(
    Output('IP', 'children'),
    Input('none', 'children')
)
def ip(_: Any) -> html.Div:
    ...

and in the layout:

...
html.Hr(),
            html.Div(
                id='none',
                children=[],
                style={'display': 'none'},
            ),
            html.Div(id="IP"),
...

But it still should be able to get this done without a callback shouldn’t it?