You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

NativeLogConfig.cs 3.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using System.Runtime.InteropServices;
  2. using System.Text;
  3. using System.Threading;
  4. using Microsoft.Extensions.Logging;
  5. namespace LLama.Native;
  6. /// <summary>
  7. /// Configure llama.cpp logging
  8. /// </summary>
  9. public static class NativeLogConfig
  10. {
  11. /// <summary>
  12. /// Callback from llama.cpp with log messages
  13. /// </summary>
  14. /// <param name="level"></param>
  15. /// <param name="message"></param>
  16. public delegate void LLamaLogCallback(LLamaLogLevel level, string message);
  17. /// <summary>
  18. /// Register a callback to receive llama log messages
  19. /// </summary>
  20. /// <param name="logCallback"></param>
  21. [DllImport(NativeApi.libraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "llama_log_set")]
  22. private static extern void native_llama_log_set(LLamaLogCallback? logCallback);
  23. /// <summary>
  24. /// A GC handle for the current log callback to ensure the callback is not collected
  25. /// </summary>
  26. private static GCHandle? _currentLogCallbackHandle;
  27. /// <summary>
  28. /// Register a callback to receive llama log messages
  29. /// </summary>
  30. /// <param name="logCallback"></param>
  31. #pragma warning disable IDE1006 // Naming Styles (name imitates llama.cpp)
  32. public static void llama_log_set(LLamaLogCallback? logCallback)
  33. #pragma warning restore IDE1006 // Naming Styles
  34. {
  35. if (NativeLibraryConfig.LibraryHasLoaded)
  36. {
  37. // The library is loaded, just pass the callback directly to llama.cpp
  38. native_llama_log_set(logCallback);
  39. // Save a GC handle, to ensure the callback is not collected
  40. _currentLogCallbackHandle?.Free();
  41. _currentLogCallbackHandle = null;
  42. if (logCallback != null)
  43. _currentLogCallbackHandle = GCHandle.Alloc(logCallback);
  44. }
  45. else
  46. {
  47. // We can't set the log method yet since that would cause the llama.dll to load.
  48. // Instead configure it to be set when the native library loading is done
  49. NativeLibraryConfig.Instance.WithLogCallback(logCallback);
  50. }
  51. }
  52. /// <summary>
  53. /// Register a callback to receive llama log messages
  54. /// </summary>
  55. /// <param name="logger"></param>
  56. #pragma warning disable IDE1006 // Naming Styles (name imitates llama.cpp)
  57. public static void llama_log_set(ILogger? logger)
  58. #pragma warning restore IDE1006 // Naming Styles
  59. {
  60. // Clear the logger
  61. if (logger == null)
  62. {
  63. llama_log_set((LLamaLogCallback?)null);
  64. return;
  65. }
  66. var builderThread = new ThreadLocal<StringBuilder>(() => new StringBuilder());
  67. // Bind a function that combines messages until a newline is encountered, then logs it all as one message
  68. llama_log_set((level, message) =>
  69. {
  70. var builder = builderThread.Value!;
  71. builder.Append(message);
  72. if (!message.EndsWith("\n"))
  73. return;
  74. // Remove the newline from the end
  75. builder.Remove(builder.Length - 1, 1);
  76. logger.Log(level.ToLogLevel(), "{message}", builder.ToString());
  77. builder.Clear();
  78. });
  79. }
  80. }