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