structured logging is great, but logging fails with variables ?

I wanted to try structured logging with os_log in C++, but I found that it fails to print anything given a format string and a variable:

eg.

void example(std::string& str)
{
    os_log_info(OS_LOG_DEFAULT, "%s", str.c_str());
    os_log_debug(OS_LOG_DEFAULT, "%s", str.c_str());
    os_log_error(OS_LOG_DEFAULT, "%s", str.c_str());   
}

This prints a blank row in the console, but with no text.

How is this meant to work with variables? It only works with literals and constants now as far as I can tell.

I'm looking forward to getting this working.

Accepted Reply

Oh, that’s interesting. Consider this tiny program:

#include <string>
#include <os/log.h>

void example(std::string& str)
{
    os_log_info(OS_LOG_DEFAULT, "'%s'", str.c_str());
    os_log_info(OS_LOG_DEFAULT, "'%{public}s'", str.c_str());
}

int main(int argc, const char * argv[]) {
    std::string s = "Hello Cruel World!";
    example(s);
    return 0;
}

The first log entry comes out as '' whereas the second is 'Hello Cruel World!'.

This relates to a key system log feature: the ability to selective log private info. By default a string is considered private, and thus you need to annotate it with {public} to have it show up in the log. Console renders a private string as <private>, but it seems that Xcode missed that memo.

This is very misleading and I encourage you to file a bug against Xcode. Please post your bug number, just for the record.

Oh, and this has nothing to do with C++ per se. The same problem affects C and probably Objective-C as well. It doesn’t affect Swift, probably because Swift interacts with the system log in a very different way than the C-based languages.

ps If you’re interesting in the system log, check out Your Friend the System Log.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • @eskimo In Xcode 15, shouldn't your first log line above print out the actual value (same as the second) when logging in Xcode 15's console? If it doesn't, then we have to mark data as globally public just do debug.

Add a Comment

Replies

Oh, that’s interesting. Consider this tiny program:

#include <string>
#include <os/log.h>

void example(std::string& str)
{
    os_log_info(OS_LOG_DEFAULT, "'%s'", str.c_str());
    os_log_info(OS_LOG_DEFAULT, "'%{public}s'", str.c_str());
}

int main(int argc, const char * argv[]) {
    std::string s = "Hello Cruel World!";
    example(s);
    return 0;
}

The first log entry comes out as '' whereas the second is 'Hello Cruel World!'.

This relates to a key system log feature: the ability to selective log private info. By default a string is considered private, and thus you need to annotate it with {public} to have it show up in the log. Console renders a private string as <private>, but it seems that Xcode missed that memo.

This is very misleading and I encourage you to file a bug against Xcode. Please post your bug number, just for the record.

Oh, and this has nothing to do with C++ per se. The same problem affects C and probably Objective-C as well. It doesn’t affect Swift, probably because Swift interacts with the system log in a very different way than the C-based languages.

ps If you’re interesting in the system log, check out Your Friend the System Log.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • @eskimo In Xcode 15, shouldn't your first log line above print out the actual value (same as the second) when logging in Xcode 15's console? If it doesn't, then we have to mark data as globally public just do debug.

Add a Comment

Ah yes. That makes a lot more sense. I did finally discover the privacy tag in the documentation, but you’re right it’s pretty misleading not to see that <private> marker. I’ll file a report as soon as I can.

By the way, is there no way to set the default to public? I just wanted to replace 100s of printfs with os_log to take advantage of the new Xcode 15 console features.

I was going to do a hack solution in which I preprocessed strings and replaced %s with %{public}s,

#define MY_LOG(fmt_, …) \
os_log_info(OS_LOG_DEFAULT, gen_public_fmt(fmt_), __VA_ARGS__)

but os_log asserts on non-constant format strings.

is there no way to set the default to public?

The system log has a huge number of configuration options. Again, I’m gonna point you to Your Friend the System Log for the links to the actual documentation.

The best approach to use depends on a bunch of factors: your platform; if it’s macOS, whether you’re building a command-line tool or an app; and so on. However, just as one specific example, if you’re targeting macOS and install a configuration profile with a com.apple.system.logging payload containing this:

<key>Subsystems</key>
<dict>
    <key>com.example.apple-samplecode.Test731121</key>
    <dict>
        <key>DEFAULT-OPTIONS</key>
        <dict>
            <key>Enable-Private-Data</key>
            <true/>
        </dict>
    </dict>
</dict>

that overrides the private nature of any log entries in the com.example.apple-samplecode.Test731121 subsystem. I ran a quick test of that today and that does seem to resolve the issue with Xcode 15 beta that brought you here.

If you’re targeting iOS, or a macOS app or appex, you should be able to do the same thing with the OSLogPreferences property in your Info.plist.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

The bug report information is here: FB12279185 (os_log fails to display <private> in Xcode 15's console when an argument is private and instead displays nothing, which is misleading)

  • Ta!

  • I think the behavior should be that you can see the private data in the Xcode console, not the word <private> or a blank. If it shows up as <private> in Xcode, it's useless for debugging, right? While working on that app, you want to see the values AND have them hidden outside of Xcode, right?

  • @eskimo - @zentrope has a good point. What IS the desired behavior within specifically the Xcode console? I can see arguments for and against showing private variables by default. Maybe you don't want sensitive data like that ever appearing on-screen, but maybe you do want to have those debugging regardless.

How would I set all logging public? The docs suggest that I have to set every subsystem and category to be public. Maybe I want the default logger to be public or several or all of them.

How would I set all logging public?

See Recording Private Data in the System Log.

IMPORTANT Pay heed to the warning that I just added to that post.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks.

By the way, I noticed: -jumping to a file and line number doesn’t seem to work in C/C++ — only Swift and Objective C(++). -structured logging doesn’t seem to give me any metadata at all when hovering over the console output when I build for iPadOS/iOS — only macOS seems to work.

jumping to a file and line number doesn’t seem to work in C/C++

That’s seems eminently bugworthy.

structured logging doesn’t seem to give me any metadata at all … when I build for iPadOS/iOS

How are you testing this?

I tried Xcode 15b1 as follows:

  • With its iOS 17 simulator. This worked as I’d expect.

  • With an iOS 16 beta device. This didn’t work; I saw old school non-structured log output.

That suggests that this requires iOS 17 beta. I could confirm that by testing with the iOS 16 simulator and an iOS 17 beta device, but I’m unable to run either of those tests at this exact moment.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Ah I guess the iPasOS version needs to be 17. For the C/C++, I assumed the issue had something to do with a dependency on the objc runtime or something, which would explain why the click to jump wasn’t working. —or maybe the compiler’s confused by all of my cross-language craziness. :) I’ll double-check.

@eskimo I've submitted another bug report regarding the missing line jumping outside of swift: FB12340549

  • Ta!

  • @eskimo I think that in cases in which objc has successfully printed, I’ve called that code from Swift. I wonder why I’m seeing this behavior. Is it possible that something is enabled only in the Swift runtime that enables jumping to line numbers?

Add a Comment