|
| 1 | +# Logging |
| 2 | + |
| 3 | +Logging in WebKit. |
| 4 | + |
| 5 | +## Setup |
| 6 | + |
| 7 | +Each framework (WebCore, WebKit, WebKitLegacy, WTF) enable their own logging infrastructure independently (though the infrastructure itself is shared). If you want to log a message, `#include` the relevant framework's `Logging.h` header. Then, you can use the macros below. |
| 8 | + |
| 9 | +Beware that you can't `#include` multiple framework's `Logging.h` headers at the same time - they each define a macro `LOG_CHANNEL_PREFIX` which will conflict with each other. Only `#include` the `Logging.h` header from your specific framework. |
| 10 | + |
| 11 | +If you want to do more advanced operations, like searching through the list of log channels, `#include` your framework's `LogInitialization.h` header. These do not conflict across frameworks, so you can do something like |
| 12 | + |
| 13 | +``` |
| 14 | +#include "LogInitialization.h" |
| 15 | +#include <WebCore/LogInitialization.h> |
| 16 | +#include <WTF/LogInitialization.h> |
| 17 | +``` |
| 18 | + |
| 19 | +Indeed, WebKit does this to initialize all frameworks' log channels during Web Process startup. |
| 20 | + |
| 21 | +## Logging messages |
| 22 | + |
| 23 | +There are a few relevant macros for logging messages: |
| 24 | + |
| 25 | +- `LOG()`: Log a printf-style message in debug builds. Requires you to name a logging channel to output to. |
| 26 | +- `LOG_WITH_STREAM()` Log an iostream-style message in debug builds. Requires you to name a logging channel to output to. |
| 27 | +- `RELEASE_LOG()`: Just like `LOG()` but logs in both debug and release builds. Requires you to name a logging channel to output to. |
| 28 | +- `WTFLogAlways()`: Mainly for local debugging, unconditionally output a message. Does not require a logging channel to output to. |
| 29 | + |
| 30 | +Here's an example invocation of `LOG()`: |
| 31 | + |
| 32 | +``` |
| 33 | +LOG(MediaQueries, "HTMLMediaElement %p selectNextSourceChild evaluating media queries", this); |
| 34 | +``` |
| 35 | + |
| 36 | +That first argument is a log channel. These have 2 purposes: |
| 37 | + |
| 38 | +- Individual channels can be enabled/disabled independently (So you can get all the WebGL logging without getting any Loading logging) |
| 39 | +- When multiple channels are enabled, and you're viewing the logs, you can search/filter by the channel |
| 40 | + |
| 41 | +Here's an example invocation of `LOG_WITH_STREAM()`: |
| 42 | + |
| 43 | +``` |
| 44 | +LOG_WITH_STREAM(Scrolling, stream << "ScrollingTree::commitTreeState - removing unvisited node " << nodeID); |
| 45 | +``` |
| 46 | + |
| 47 | +The macro sets up a local variable named `stream` which the second argument can direct messages to. The second argument is a collection of statements - not expressions like `LOG()` and `RELEASE_LOG()`. So, you can do things like this: |
| 48 | + |
| 49 | +``` |
| 50 | +LOG_WITH_STREAM(TheLogChannel, |
| 51 | + for (const auto& something : stuffToLog) |
| 52 | + stream << " " << something; |
| 53 | +); |
| 54 | +``` |
| 55 | + |
| 56 | +The reason why (most of) these use macros is so the entire thing can be compiled out when logging is disabled. Consider this: |
| 57 | + |
| 58 | +``` |
| 59 | +LOG(TheLogChannel, "The result is %d", someSuperComplicatedCalculation()); |
| 60 | +``` |
| 61 | + |
| 62 | +If these were not macros, you'd have to pay for `someSuperComplicatedCalculation()` whether logging is enabled or not. |
| 63 | + |
| 64 | +## Enabling and disabling log channels |
| 65 | + |
| 66 | +Channels are enabled/disabled at startup by passing a carefully crafted string to `initializeLogChannelsIfNecessary()`. On the macOS and iOS ports, this string comes from the _defaults_ database. On other UNIX systems and Windows, it comes from environment variables. |
| 67 | + |
| 68 | +You can read the grammar of this string in `initializeLogChannelsIfNecessary()`. Here is an example: |
| 69 | + |
| 70 | +``` |
| 71 | +WebGL -Loading |
| 72 | +``` |
| 73 | + |
| 74 | +You can also specify the string `all` to enable all logging. |
| 75 | + |
| 76 | +On macOS/iOS and Windows, each framework has its own individually supplied string that it uses to enable its own logging channels. On Linux, all frameworks share the same string. |
| 77 | + |
| 78 | +### Linux |
| 79 | + |
| 80 | +Set the `WEBKIT_DEBUG` environment variable. |
| 81 | + |
| 82 | +``` |
| 83 | +WEBKIT_DEBUG=Scrolling Tools/Scripts/run-minibrowser --gtk --debug |
| 84 | +``` |
| 85 | + |
| 86 | +### macOS |
| 87 | + |
| 88 | +On macOS, you can, for example, enable the `Language` log channel with these terminal commands: |
| 89 | + |
| 90 | +``` |
| 91 | +for identifier in com.apple.WebKit.WebContent.Development com.apple.WebKit.WebContent org.webkit.MiniBrowser com.apple.WebKit.WebKitTestRunner org.webkit.DumpRenderTree -g /Users/$USER/Library/Containers/com.apple.Safari/Data/Library/Preferences/com.apple.Safari.plist; do |
| 92 | + for key in WTFLogging WebCoreLogging WebKitLogging WebKit2Logging; do |
| 93 | + defaults write ${identifier} "${key}" "Language" |
| 94 | + done |
| 95 | +done |
| 96 | +``` |
| 97 | + |
| 98 | +You may also need to specify these strings to `com.apple.WebKit.WebContent.Development`, the global domain, or the Safari container, depending on what you're running. |
| 99 | + |
| 100 | +You may also pass this key and value as an argument: |
| 101 | + |
| 102 | +``` |
| 103 | +Tools/Scripts/run-minibrowser --debug -WebCoreLogging Scrolling |
| 104 | +``` |
| 105 | + |
| 106 | +### Windows |
| 107 | + |
| 108 | +Set the `WebCoreLogging` environment variable. |
| 109 | + |
| 110 | +## Adding a new log channel |
| 111 | + |
| 112 | +Simply add a line to your framework's `Logging.h` header. Depending on how the accompanying `Logging.cpp` file is set up, you may need to add a parallel line there. That should be all you need. It is acceptable to have log channels in different frameworks with the same name - this is what `LOG_CHANNEL_PREFIX` is for. |
0 commit comments