diff --git a/src/Extism.Sdk/LibExtism.cs b/src/Extism.Sdk/LibExtism.cs index 4777917..795f3d4 100644 --- a/src/Extism.Sdk/LibExtism.cs +++ b/src/Extism.Sdk/LibExtism.cs @@ -289,7 +289,7 @@ internal struct ExtismPlugin { } unsafe internal static extern IntPtr extism_plugin_output_data(ExtismPlugin* plugin); /// - /// Set log file and level. + /// Set log file and level for file logger. /// /// /// @@ -298,40 +298,28 @@ internal struct ExtismPlugin { } internal static extern bool extism_log_file(string filename, string logLevel); /// - /// Get Extism Runtime version. + /// Enable a custom log handler, this will buffer logs until `extism_log_drain` is called. + /// this will buffer logs until `extism_log_drain` is called /// + /// /// [DllImport("extism")] - internal static extern IntPtr extism_version(); + internal static extern bool extism_log_custom(string logLevel); + + internal delegate void LoggingSink(string line, ulong length); /// - /// Extism Log Levels + /// Calls the provided callback function for each buffered log line. + /// This is only needed when `extism_log_custom` is used. /// - internal static class LogLevels - { - /// - /// Designates very serious errors. - /// - internal const string Error = "Error"; - - /// - /// Designates hazardous situations. - /// - internal const string Warn = "Warn"; - - /// - /// Designates useful information. - /// - internal const string Info = "Info"; - - /// - /// Designates lower priority information. - /// - internal const string Debug = "Debug"; + /// + [DllImport("extism")] + internal static extern void extism_log_drain(LoggingSink callback); - /// - /// Designates very low priority, often extremely verbose, information. - /// - internal const string Trace = "Trace"; - } + /// + /// Get Extism Runtime version. + /// + /// + [DllImport("extism")] + internal static extern IntPtr extism_version(); } diff --git a/src/Extism.Sdk/LogLevel.cs b/src/Extism.Sdk/LogLevel.cs index e085f8d..5907ee2 100644 --- a/src/Extism.Sdk/LogLevel.cs +++ b/src/Extism.Sdk/LogLevel.cs @@ -8,12 +8,12 @@ public enum LogLevel /// /// Designates very serious errors. /// - Error, + Error = 1, /// /// Designates hazardous situations. /// - Warning, + Warn, /// /// Designates useful information. diff --git a/src/Extism.Sdk/Plugin.cs b/src/Extism.Sdk/Plugin.cs index 42bfd9e..c35bb1f 100644 --- a/src/Extism.Sdk/Plugin.cs +++ b/src/Extism.Sdk/Plugin.cs @@ -317,4 +317,44 @@ public static string ExtismVersion() var version = LibExtism.extism_version(); return Marshal.PtrToStringAnsi(version); } -} \ No newline at end of file + + /// + /// Set log file and level + /// + /// Log file path + /// Minimum log level + public static void ConfigureFileLogging(string path, LogLevel level) + { + var logLevel = Enum.GetName(typeof(LogLevel), level).ToLowerInvariant(); + LibExtism.extism_log_file(path, logLevel); + } + + /// + /// Enable a custom log handler, this will buffer logs until is called. + /// + /// + public static void ConfigureCustomLogging(LogLevel level) + { + var logLevel = Enum.GetName(typeof(LogLevel), level).ToLowerInvariant(); + LibExtism.extism_log_custom(logLevel); + } + + /// + /// Calls the provided callback function for each buffered log line. + /// This only needed when is used. + /// + /// + public static void DrainCustomLogs(LoggingSink callback) + { + LibExtism.extism_log_drain((line, length) => + { + callback(line); + }); + } +} + +/// +/// Custom logging callback. +/// +/// +public delegate void LoggingSink(string line); \ No newline at end of file diff --git a/test/Extism.Sdk/BasicTests.cs b/test/Extism.Sdk/BasicTests.cs index 97a344c..8bd29f5 100644 --- a/test/Extism.Sdk/BasicTests.cs +++ b/test/Extism.Sdk/BasicTests.cs @@ -1,5 +1,7 @@ using Extism.Sdk.Native; + using Shouldly; + using System.Runtime.InteropServices; using System.Text; @@ -178,6 +180,51 @@ public void HostFunctionsWithMemory() Encoding.UTF8.GetString(response).ShouldBe("HELLO FRODO!"); } + [Fact] + public void FileLog() + { + var tempFile = Path.GetTempFileName(); + Plugin.ConfigureFileLogging(tempFile, LogLevel.Warn); + using (var plugin = Helpers.LoadPlugin("log.wasm")) + { + plugin.Call("run_test", Array.Empty()); + } + + // HACK: tempFile gets locked by the Extism runtime + var tempFile2 = Path.GetTempFileName(); + File.Copy(tempFile, tempFile2, true); + + var content = File.ReadAllText(tempFile2); + content.ShouldContain("warn"); + content.ShouldContain("error"); + content.ShouldNotContain("info"); + content.ShouldNotContain("debug"); + content.ShouldNotContain("trace"); + } + + + // [Fact] + // Interferes with FileLog + internal void CustomLog() + { + var builder = new StringBuilder(); + + Plugin.ConfigureCustomLogging(LogLevel.Warn); + using (var plugin = Helpers.LoadPlugin("log.wasm")) + { + plugin.Call("run_test", Array.Empty()); + } + + Plugin.DrainCustomLogs(line => builder.AppendLine(line)); + + var content = builder.ToString(); + content.ShouldContain("warn"); + content.ShouldContain("error"); + content.ShouldNotContain("info"); + content.ShouldNotContain("debug"); + content.ShouldNotContain("trace"); + } + public class CountVowelsResponse { public int Count { get; set; } diff --git a/test/Extism.Sdk/Extism.Sdk.Tests.csproj b/test/Extism.Sdk/Extism.Sdk.Tests.csproj index 8c22e58..bb8d0b0 100644 --- a/test/Extism.Sdk/Extism.Sdk.Tests.csproj +++ b/test/Extism.Sdk/Extism.Sdk.Tests.csproj @@ -1,4 +1,4 @@ - + net7.0