Native logging and profiling
Log functions
The engine exposes severity-specific log functions:
logTrace, logDebug, logInfo, logNotice,
logWarning, logError,
logCritical, and logHack.
Current logging adapters commonly call them as
logFunction(prefix, message, metadata), with None for unused metadata.
logExceptionFrame(exceptionType, exception, frame) records an exception from
a specific Python frame. flushPythonLog() forces buffered Python log output
to be written; periodic flushing is infrastructure behavior, not something
each mod should schedule independently.
Use the standard Python logging layer for mods. It already maps levels to the
native functions and avoids depending on their raw signature. Keep high-rate
hooks quiet and never include secrets, authentication data, or private
endpoints.
Profiling helpers
uniprofSceneStart()marks a new rendered scene after an arena, hangar, or offline space becomes ready.uniprofRegionEnter(label, color)returns a region handle;uniprofRegionExit(handle)closes that exact region.PFbeginFrame(logID)andPFendFrame()bracket a measured Python operation.enableBattleStatisticCollector,wg_getClientStatistics,wg_getHangarStatistics,getFPS,getBattleFPS,statPing, andstatLagDetectedexpose diagnostics or telemetry state.
Diagnostics and JSON bridges must serialize the four numeric components explicitly or publish a deliberately selected component. Do not stringify the native object and call that a stable schema; verify the component meanings at the consuming call site.
Profiling pairs require try/finally ownership so an exception cannot leave a
region open. They are diagnostic infrastructure, not gameplay timers.
Preferences, paths, and native persistence
Preference path
wg_getPreferencesFilePath() returns the path of the active preferences file.
Python 2 callers convert the returned UTF-8 byte string before using it with
Unicode filesystem paths. The containing directory is the client-owned
persistent data root used for account caches and selected mod data.
Some compatibility layers fall back to getPreferencesFilePath(). Treat the
wg_ spelling as current and the unprefixed spelling as a guarded fallback.
Use the directory, not the preferences XML itself, for separate application or mod files. Normalize joined paths, create only owned subdirectories, and do not overwrite client caches.
Preference callbacks
wg_subscribeToReadPreferences(callback)registers a callback receiving the preferences root when native preferences are read.wg_subscribeToSavePreferences(callback)registers a callback receiving the preferences root during save.wg_preferencesExistedAtStartup()distinguishes a first/default startup from a client that loaded an existing preferences file.savePreferences()asks the engine to save video, graphics, and script preferences.
These callbacks are intended for settings infrastructure. A mod with its own JSON configuration should normally own that file explicitly instead of injecting arbitrary state into the client preferences tree.
Owned preferences directory
The reliable primitive to verify in current client builds is the preferences file path helper,
commonly exposed as wg_getPreferencesFilePath() with older compatibility fallbacks
in some builds. Do not assume that a getPreferencesDir()-style helper exists unless
the target build actually exposes it.
For separate mod data, derive an owned directory from the preferences file path and create a subdirectory with a stable generic name. Never write arbitrary data into the client preferences XML or overwrite client-owned caches.
import os
import BigWorld
import logging
LOG = logging.getLogger('mod.example.storage')
def _preferences_file_path():
getter = getattr(BigWorld, 'wg_getPreferencesFilePath', None)
if getter is None:
getter = getattr(BigWorld, 'getPreferencesFilePath', None)
if getter is None:
LOG.warning('Preferences path helper is unavailable in this build')
return None
return getter()
def _owned_storage_dir():
prefs = _preferences_file_path()
if not prefs:
return None
root = os.path.dirname(os.path.abspath(prefs))
path = os.path.join(root, 'mods', 'example')
if not os.path.isdir(path):
os.makedirs(path)
return path
Logging through named loggers
The native debug functions exist for engine infrastructure, but normal mod diagnostics should
usually go through Python's logging module. A named logger gives the log a stable
owner and keeps high-rate hooks filterable.
- Use one module-level logger per single-file mod or per broad subsystem section.
- Use
logger.exceptiononly inside exception handlers. - Keep per-frame logging disabled or behind explicit diagnostics.
- Do not log tokens, private endpoints, filesystem dumps, or full account data.