|
- using LLama.Native;
- using System;
- using System.Diagnostics;
- using System.IO;
- using static LLama.Common.ILLamaLogger;
-
- namespace LLama.Common;
-
- /// <summary>
- /// receives log messages from LLamaSharp
- /// </summary>
- public interface ILLamaLogger
- {
- /// <summary>
- /// Severity level of a log message
- /// </summary>
- public enum LogLevel
- {
- /// <summary>
- /// Logs that are used for interactive investigation during development.
- /// </summary>
- Debug = 1,
-
- /// <summary>
- /// Logs that highlight when the current flow of execution is stopped due to a failure.
- /// </summary>
- Error = 2,
-
- /// <summary>
- /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the application execution to stop.
- /// </summary>
- Warning = 3,
-
- /// <summary>
- /// Logs that track the general flow of the application.
- /// </summary>
- Info = 4
- }
-
- /// <summary>
- /// Write the log in customized way
- /// </summary>
- /// <param name="source">The source of the log. It may be a method name or class name.</param>
- /// <param name="message">The message.</param>
- /// <param name="level">The log level.</param>
- void Log(string source, string message, LogLevel level);
- }
-
- /// <summary>
- /// The default logger of LLamaSharp. On default it write to console. Use methods of `LLamaLogger.Default` to change the behavior.
- /// It's recommended to inherit `ILLamaLogger` to customize the behavior.
- /// </summary>
- public sealed class LLamaDefaultLogger
- : ILLamaLogger
- {
- private static readonly Lazy<LLamaDefaultLogger> _instance = new Lazy<LLamaDefaultLogger>(() => new LLamaDefaultLogger());
-
- private bool _toConsole = true;
- private bool _toFile;
-
- private FileStream? _fileStream;
- private StreamWriter? _fileWriter;
-
- /// <summary>
- /// Get the default logger instance
- /// </summary>
- public static LLamaDefaultLogger Default => _instance.Value;
-
- private LLamaDefaultLogger()
- {
-
- }
-
- /// <summary>
- /// Enable logging output from llama.cpp
- /// </summary>
- /// <returns></returns>
- public LLamaDefaultLogger EnableNative()
- {
- EnableNativeLogCallback();
- return this;
- }
-
- /// <summary>
- /// Enable writing log messages to console
- /// </summary>
- /// <returns></returns>
- public LLamaDefaultLogger EnableConsole()
- {
- _toConsole = true;
- return this;
- }
-
- /// <summary>
- /// Disable writing messages to console
- /// </summary>
- /// <returns></returns>
- public LLamaDefaultLogger DisableConsole()
- {
- _toConsole = false;
- return this;
- }
-
- /// <summary>
- /// Enable writing log messages to file
- /// </summary>
- /// <param name="filename"></param>
- /// <param name="mode"></param>
- /// <returns></returns>
- public LLamaDefaultLogger EnableFile(string filename, FileMode mode = FileMode.Append)
- {
- _fileStream = new FileStream(filename, mode, FileAccess.Write);
- _fileWriter = new StreamWriter(_fileStream);
- _toFile = true;
- return this;
- }
-
- /// <summary>
- /// Disable writing log messages to file
- /// </summary>
- /// <param name="filename">unused!</param>
- /// <returns></returns>
- [Obsolete("Use DisableFile method without 'filename' parameter")]
- public LLamaDefaultLogger DisableFile(string filename)
- {
- return DisableFile();
- }
-
- /// <summary>
- /// Disable writing log messages to file
- /// </summary>
- /// <returns></returns>
- public LLamaDefaultLogger DisableFile()
- {
- if (_fileWriter is not null)
- {
- _fileWriter.Close();
- _fileWriter = null;
- }
- if (_fileStream is not null)
- {
- _fileStream.Close();
- _fileStream = null;
- }
- _toFile = false;
- return this;
- }
-
- /// <summary>
- /// Log a message
- /// </summary>
- /// <param name="source">The source of this message (e.g. class name)</param>
- /// <param name="message">The message to log</param>
- /// <param name="level">Severity level of this message</param>
- public void Log(string source, string message, LogLevel level)
- {
- if (level == LogLevel.Info)
- {
- Info(message);
- }
- else if (level == LogLevel.Debug)
- {
-
- }
- else if (level == LogLevel.Warning)
- {
- Warn(message);
- }
- else if (level == LogLevel.Error)
- {
- Error(message);
- }
- }
-
- /// <summary>
- /// Write a log message with "Info" severity
- /// </summary>
- /// <param name="message"></param>
- public void Info(string message)
- {
- message = MessageFormat("info", message);
- if (_toConsole)
- {
- Console.ForegroundColor = ConsoleColor.White;
- Console.WriteLine(message);
- Console.ResetColor();
- }
- if (_toFile)
- {
- Debug.Assert(_fileStream is not null);
- Debug.Assert(_fileWriter is not null);
- _fileWriter.WriteLine(message);
- }
- }
-
- /// <summary>
- /// Write a log message with "Warn" severity
- /// </summary>
- /// <param name="message"></param>
- public void Warn(string message)
- {
- message = MessageFormat("warn", message);
- if (_toConsole)
- {
- Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine(message);
- Console.ResetColor();
- }
- if (_toFile)
- {
- Debug.Assert(_fileStream is not null);
- Debug.Assert(_fileWriter is not null);
- _fileWriter.WriteLine(message);
- }
- }
-
- /// <summary>
- /// Write a log message with "Error" severity
- /// </summary>
- /// <param name="message"></param>
- public void Error(string message)
- {
- message = MessageFormat("error", message);
- if (_toConsole)
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine(message);
- Console.ResetColor();
- }
- if (_toFile)
- {
- Debug.Assert(_fileStream is not null);
- Debug.Assert(_fileWriter is not null);
- _fileWriter.WriteLine(message);
- }
- }
-
- private static string MessageFormat(string level, string message)
- {
- var now = DateTime.Now;
- return $"[{now:yyyy.MM.dd HH:mm:ss}][{level}]: {message}";
- }
-
- /// <summary>
- /// Register native logging callback
- /// </summary>
- private void EnableNativeLogCallback()
- {
- // TODO: Move to a more appropriate place once we have a intitialize method
- NativeApi.llama_log_set(NativeLogCallback);
- }
-
- /// <summary>
- /// Callback for native logging function
- /// </summary>
- /// <param name="level">The log level</param>
- /// <param name="message">The log message</param>
- private void NativeLogCallback(LogLevel level, string message)
- {
- if (string.IsNullOrEmpty(message))
- return;
-
- // Note that text includes the new line character at the end for most events.
- // If your logging mechanism cannot handle that, check if the last character is '\n' and strip it
- // if it exists.
- // It might not exist for progress report where '.' is output repeatedly.
- Log(default!, message.TrimEnd('\n'), level);
- }
-
- }
|