Skip to content

[posix] -d/--debug-level has no effect: the level is set before the instance is constructed #13625

Description

@clara-mostly-human

Describe the bug

On the posix platform, ot-daemon -d <level> (and ot-cli -d <level>) does not change the log level. The process keeps logging at OPENTHREAD_CONFIG_LOG_LEVEL_INIT, which openthread-core-posix-config.h sets to OT_LOG_LEVEL_CRIT, whatever is passed.

The cause is an ordering problem in src/posix/main.c, InitInstance():

IgnoreError(otLoggingSetLevel(aConfig->mLogLevel));

instance = otSysInit(&aConfig->mPlatformConfig);

In a single-instance build otLoggingSetLevel() is Instance::Get().SetLogLevel(level), and Instance::Get() returns the raw static buffer. At this point no Instance has been constructed in it yet, so SetLogLevel() writes mLogLevel into uninitialised storage (and calls SignalLogLevelChange() on it). otSysInit() then reaches Instance::InitSingle(), whose placement-new runs the constructor:

, mLogLevel(static_cast<LogLevel>(OPENTHREAD_CONFIG_LOG_LEVEL_INIT))

which puts the level back to CRIT. The value from -d is lost, and because of IgnoreError nothing reports it.

To Reproduce

Commit 87e6c37, macOS 26 (arm64); nothing in the path above is platform-specific.

  1. Build the posix daemon with -DOT_LOG_LEVEL=DEBG -DOT_FULL_LOGS=ON.
  2. sudo ot-daemon -v -d 4 'spinel+hdlc+forkpty://<ot-rcp>?forkpty-arg=1', then form a network with ot-ctl.
  3. Only the four syslog(LOG_INFO, ...) lines from main.c appear (Running ..., Thread version, Thread interface, RCP version); no core log lines at all.
  4. After ot-ctl log level 4 the core logs appear as expected.

Expected behavior

-d <level> sets the initial log level. Calling otLoggingSetLevel() after otSysInit() returns would do it, at the cost of the log lines emitted during otSysInit() itself; alternatively the level could be carried into the instance another way. Happy to send a PR for whichever you prefer.

Values above 5 (e.g. -d 7, a habit from otbr-agent) are rejected by SetLogLevel() with kErrorInvalidArgs, which is also swallowed by the IgnoreError; a warning there would help.

Additional context

Possibly related, but not root-caused: in the same setup, raising the level to debug at run time with ot-ctl log level 5 was followed by the daemon going away. The last line it logged was [D] Cli-----------: Output: Done, after which every ot-ctl call got connect session failed: Connection refused; no crash report was written. ot-ctl log level 4 does not have this effect. I have seen this once and have not investigated further, so please treat it as an observation rather than a diagnosis; I can open a separate issue with a proper reproduction if that is useful.

Activity

  1. EskoDijk commented on Sep 19, 2026

    @EskoDijk
    Contributor

    Commit cb4b28313 made the log level settable per instance. This might have been the moment that -d stopped working.

  2. abtink commented on Sep 21, 2026

    @abtink
    Member

    Thanks. Submitted PR:


    There is an unfortunate flaw in the logging architecture. OT core expects the platform to provide logging via the otPlatLog() API, yet the platform layer itself uses the core otLogPlat APIs to log from some of its own modules. This creates a circular dependency that is unfortunately not eay to untangle at this point.

  3. abtink commented on Sep 22, 2026

    @abtink
    Member

    Submitted PR:

    I suspect platforms other than posix may do the exact same thing (it is unfortunate due to the circular use I pointed out earlier). This PR provides a functional workaround for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions