[Lldb-commits] [PATCH] D27459: Straw-man proposal for new logging syntax

Zachary Turner via Phabricator via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 6 09:47:00 PST 2016

zturner added a comment.

In https://reviews.llvm.org/D27459#614670, @clayborg wrote:

> Part of the reason I like the current "if (log) log->Printf()" is that it doesn't cost you much if logging isn't enabled. So if you have a log line like:
>   if (log)
>     log->Printf("%s %s %s", myStringRef1.str().c_str(), myStringRef2.str().c_str(), myStringRef3.str().c_str());
> And switch over to using:
>   LLDB_LOG() << myStringRef1 << " " << myStringRef2 << " " << myStringRef2;
> You end up doing some work with all of the types regardless of wether the logging is enabled. We tend to do pretty heavy logging in places and I really don't want performance impacted (the expression parser emits a full novel worth of information when logging is enabled), nor would I want people to log less because they are worried about affecting performance.
> So any solution should have very minimal cost if logging isn't enabled. We also do log channels, so any design will need to include the ability to log to a channel, any channel, or only if all channels are enabled.
> The other thing I don't like about streams is they are harder to read over a printf style log string. I wrote all of dwarfdump and used the full power off C++ streams and I regret doing this as all of the code is really hard to read. I also didn't like the fact that streams maintain state and can affect things down the line. If we adopt LLVM style streams I believe they don't suffer from the C++ streams having state issue. But with C++ you can do this:

Take a look at `llvm::formatv`.  I wrote this in LLVM specifically to be the best of both worlds.  You get all the flexibility and conciseness of printf with all the type safety of streams.  Example:

  // Printf style
  log->Printf("%d %s %z", 12, "test", (size_t)7);
  // Stream style
  *log << 12 << "test" << (size_t)7;
  // formatv style
  *log << llvm::formatv("{0} {1} {2}", 12, "test", (size_t)7);
  // alternative formatv sytle
  log->Formatv("{0} {1} {2}", 12, "test", (size_t)7);

As you can see, you don't have to specify the type.  All the ugliness about `PRIx64`, compiler inconsistencies, platform-dependent sizes, etc all disappear because it deduces the type.  And it's even better than this, because you can write custom formatters for your own types.  For examples, LLDB has a class called `AddressRange`.  With printf you would have to write this `log->Printf("%llu - %llu", range.first(), range.second())', but with `formatv` you can write this: `log->Formatv("{0}", range);` as long as it can find a formatter somewhere.  And formatters can define arbitrary style options too, so you could write something like `log->Formatv("{0:abc}", range);` and this string "abc" would get passed to the formatter's format function.  This is useful when a type is often formatted different ways (precision, optional fields, etc).

I strongly recommend moving to this for all printf style formatting moving forward.


More information about the lldb-commits mailing list