Skip to content

Commit

Permalink
Added support for "Log" in mod.json
Browse files Browse the repository at this point in the history
  • Loading branch information
CptMoore committed Dec 1, 2024
1 parent b809b25 commit 4ce47ce
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 3 deletions.
12 changes: 11 additions & 1 deletion ModTek/Features/Logging/LoggingFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal static class LoggingFeature

private static AppenderUnityConsole _consoleLog;
private static AppenderFile _mainLog;
private static AppenderFile[] _logsAppenders = Array.Empty<AppenderFile>();
private static AppenderFile[] _logsAppenders = [];

private static MTLoggerAsyncQueue _queue;

Expand Down Expand Up @@ -76,6 +76,16 @@ internal static void AddAppenders(string basePath, Dictionary<string, AppenderSe
_logsAppenders = logsAppenders;
}

internal static void AddModLogAppender(string logPath, string loggerName)
{
var logsAppenders = new AppenderFile[_logsAppenders.Length + 1];
Array.Copy(_logsAppenders, logsAppenders, _logsAppenders.Length);
var index = _logsAppenders.Length;
var settings = new AppenderSettings { Includes = [new FilterSettings { LoggerNames = [loggerName] }] };
logsAppenders[index] = new AppenderFile(logPath, settings);
_logsAppenders = logsAppenders;
}

// used for intercepting all logging attempts and to log centrally
internal static void LogAtLevel(string loggerName, LogLevel logLevel, object message, Exception exception, IStackTrace location)
{
Expand Down
5 changes: 5 additions & 0 deletions ModTek/Features/Manifest/Mods/ModDefExLoading.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ internal static bool LoadMod(ModDefEx modDef, out string reason)

// setup logs before calling the assembly
LoggingFeature.AddAppenders(modDef.Directory, modDef.Logs);
if (modDef.Log != null)
{
var logPath = Path.Combine(modDef.Directory, modDef.Log.FilePath);
LoggingFeature.AddModLogAppender(logPath, modDef.Log.LoggerName);
}

// load the mod assembly
if (modDef.DLL != null && !LoadAssemblyAndCallInit(modDef))
Expand Down
17 changes: 16 additions & 1 deletion ModTek/Features/Manifest/Public/ModDefEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,25 @@ public override bool Equals(object obj)
// these will be different depending on the mod obviously
public JObject Settings { get; set; } = new();

// TODO to be removed in the future or kept undocumented
// complex setup of log files, same complexity as ModTek itself
[JsonProperty]
internal const string Logs_Description = "Allows to define logs, the `key` specifies the log file path relative to `the mods directory`.";
[JsonProperty]
internal Dictionary<string, AppenderSettings> Logs { get; set; }

// simplified dedicated log file setup for mods
[JsonProperty]
internal const string Log_Description = "Allows to define a log relative to the mods directory, that will contain a copy of all log statements for the specified logger.";
[JsonProperty]
internal ModLogSettings Log { get; set; }
internal class ModLogSettings
{
[JsonProperty(Required = Required.Always)]
internal string FilePath { get; set; }
[JsonProperty(Required = Required.Always)]
internal string LoggerName { get; set; }
}

[JsonIgnore]
public bool LoadFail { get; set; }
Expand All @@ -141,7 +156,7 @@ internal void SaveState()
var modStatePath = Path.Combine(Directory, ModTek.MOD_STATE_JSON_NAME);
var state = new ModState();
state.Enabled = Enabled;
Log.Main.Info?.Log("\t\twriting to FS:" + QuotedName + "->" + state.Enabled);
global::ModTek.Log.Main.Info?.Log("\t\twriting to FS:" + QuotedName + "->" + state.Enabled);
state.SaveToPath(modStatePath);
}

Expand Down
21 changes: 20 additions & 1 deletion doc/LOGGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ModTek logging has the following features:
- Provides filter options to determine what does or does not get into the log.
- Formats a log message so that it includes a logger name, nicely formatted time, thread id if not on main thread, log message and possibly an exception.
- Uses a high precision timer, to allow 1/10 of microsecond precision (10^-7) for time stamps instead of milliseconds (10^-3).
- Supports adding additional log files. (TODO allow mods to define the log files directly in mod.json, right now only possible via `ModTek/config.json`)
- Supports adding additional log files through `ModTek/config.json`.
- Added more log levels, use "200" for Trace logging and "250" for Fatal logging. In C# enums are ints, so casting a integer to HBS' LogLevel is valid, `(LogLevel)200`.
- Log rotation per game start. Logs are rotated to survive at least one other start, logs that end with `.1` are from a previous application start.

Expand Down Expand Up @@ -68,8 +68,26 @@ In the advanced merge json example from before, set 200 as the log level for you
}
```

### Mod Local Logs

> **Note**
> It is not recommended to use this feature as it produces duplicate IO
If a mod author wants to have a separate copy of all logs a logger produces, one can enable a separate log in `mod.json`:
```json
{
"Log": {
"FilePath": "log.txt",
"LoggerName": "YourMod"
}
}
```

### Nullable loggers

> **Note**
> Nullable loggers is an advanced feature only necesary if one takes the time to use it
Another way of enhancing performance is using nullable loggers. This is only for advanced users requiring lots of performance while still wanting readable code.

In C# one can use Null-conditional operators to check for null and skip code from executing.
Expand Down Expand Up @@ -109,3 +127,4 @@ if (nullableLogger != null)
There is a caveat, the game changes log levels after the mods have initialized, so in order to keep up there is a Harmony patch required and some boilerplate code.

For the boilerplate code, see [NullableLogger.cs](../ModTek/NullableLogger.cs) and [Log.cs](../ModTek/Log.cs) as used by ModTek itself.
ModTek comments out some parts in `NullableLogger.cs` and replaces them with internal calls, these would need to be reverted back.

0 comments on commit 4ce47ce

Please sign in to comment.