Skip to content

Commit

Permalink
refactor: Refactoring using the Adapter design pattern
Browse files Browse the repository at this point in the history
* 采用适配器设计模式重构 logger handle、sink handle
* 修复 Logger.Get() 可能泄露 handle 的问题
* 修复 Logger.AddSink(), Logger.DropSink(), Logger.SetErrorHandler() 的线程安全问题
* Logger.DropSink() 返回值由 bool -> void
* 重构 Logger 的错误处理器
     Logger.SetErrorHandler(Log4spErrorCallback callback); -> Logger.SetErrorHandler(LoggerErrorHandler handler);
     Log4spErrorCallback -> LoggerErrorHandler
     function void (const char[] msg); -> function void (Logger logger, const char[] msg);
* 恢复了 Logger.***AmxTpl() API
     与之前相同,依然使用 SM 提供的 format
     会中断 sourcepawn 代码
     长度超过 2048 会被截断
     格式化存在 BUG(alliedmodders/sourcemod#2221)
     但是性能应该稍快一点 (5~8%)
* 增强宏 LOG4SP_NO_EXT
* 更新注释文档
* 重命名 sink 构造函数参数 async -> multiThread
* 重构 Sink 过滤器 ClientChatSinkFilter -> SinkClientFilter
* 移除 Sink 多余的记录日志 API(只保留一个记录原始日志的API)
  • Loading branch information
F1F88 committed Dec 2, 2024
1 parent f7a0973 commit c16ab81
Show file tree
Hide file tree
Showing 52 changed files with 2,149 additions and 2,254 deletions.
8 changes: 4 additions & 4 deletions PackageScript
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ folder_list = [
'addons/sourcemod/scripting/include',
'addons/sourcemod/scripting/include/log4sp',
'addons/sourcemod/scripting/include/log4sp/sinks',
'addons/sourcemod/scripting/include/log4sp_empty',
'addons/sourcemod/scripting/include/log4sp_empty/sinks',
'addons/sourcemod/scripting/include/log4sp_no_ext',
'addons/sourcemod/scripting/include/log4sp_no_ext/sinks',
#'addons/sourcemod/gamedata',
#'addons/sourcemod/configs',
]
Expand Down Expand Up @@ -52,13 +52,13 @@ CopyFiles('sourcemod/scripting/include/log4sp/sinks', 'addons/sourcemod/scriptin
'client_console_sink.inc'
]
)
CopyFiles('sourcemod/scripting/include/log4sp_empty', 'addons/sourcemod/scripting/include/log4sp_empty',
CopyFiles('sourcemod/scripting/include/log4sp_no_ext', 'addons/sourcemod/scripting/include/log4sp_no_ext',
[
'common.inc',
'logger.inc'
]
)
CopyFiles('sourcemod/scripting/include/log4sp_empty/sinks', 'addons/sourcemod/scripting/include/log4sp_empty/sinks',
CopyFiles('sourcemod/scripting/include/log4sp_no_ext/sinks', 'addons/sourcemod/scripting/include/log4sp_no_ext/sinks',
[
'sink.inc',
'server_console_sink.inc',
Expand Down
2 changes: 1 addition & 1 deletion sourcemod/scripting/include/log4sp/common.inc
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ native void LogLevelToShortName(LogLevel lvl, char[] buffer, int maxlen);
* Convert a logging level name to log level enum.
*
* @param name Log level name.
* @return Logging level enum or LogLevel_Off when the log level name does not exist.
* @return Logging level enum or LogLevel_Off when the logging level name does not exist.
*/
native LogLevel NameToLogLevel(const char[] name);
114 changes: 62 additions & 52 deletions sourcemod/scripting/include/log4sp/logger.inc
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,43 @@
#include <log4sp/sinks/sink>


typeset Log4spErrorCallback
typeset LoggerErrorHandler
{
function void (const char[] msg);
function void (Logger logger, const char[] msg);
};


methodmap Logger < Handle
{
/**
* Creating logger handle manually.
* Creating a logger handle manually.
*
* @param name The name of the new logger.
* @param sinks The sinks array to be added to the new logger.
* @param numSinks The number of slots in the sinks array.
* @param async If true, the sink of the new logger will be multi threaded.
* @param policy Message queue overflow policy. (Only used when async=true)
* @param async If true, Log operations will be pushed to background threads for processing,
* which can avoid blocking the main thread.
* @param policy Message queue overflow policy. (Only used when async = true)
* @return Logger handle.
* @error Logger name already exits, or the sinks has an invalid handle.
*/
public native Logger(const char[] name, Sink[] sinks, int numSinks, bool async = false, AsyncOverflowPolicy policy = AsyncOverflowPolicy_Block);

/**
* Get a logger handle by logger name.
* Gets a logger handle by logger name.
*
* @param name The name of the logger.
* @return Return an existing logger handle or INVALID_HANDLE if a logger with such name doesn't exist.
* @return Logger handle or INVALID_HANDLE if the logger name does not exist.
*/
public static native Logger Get(const char[] name);

/**
* Create a logger handle that outputs to the server console.
*
* @param name The name of the new logger.
* @param async If true, the sink of the new logger will be multi threaded.
* @param policy Message queue overflow policy. (Only used when async=true)
* @param async If true, Log operations will be pushed to background threads for processing,
* which can avoid blocking the main thread.
* @param policy Message queue overflow policy. (Only used when async = true)
* @return Logger handle.
* @error Logger name already exits.
*/
Expand All @@ -56,8 +58,9 @@ methodmap Logger < Handle
* @param name The name of the new logger.
* @param file The file path where the log messages will be written.
* @param truncate If true, the created file will be truncated.
* @param async If true, the sink of the new logger will be multi threaded.
* @param policy Message queue overflow policy. (Only used when async=true)
* @param async If true, Log operations will be pushed to background threads for processing,
* which can avoid blocking the main thread.
* @param policy Message queue overflow policy. (Only used when async = true)
* @return Logger handle.
* @error Logger name already exits.
*/
Expand All @@ -81,8 +84,9 @@ methodmap Logger < Handle
* @param maxFileSize The maximum size of the log file in bytes before it gets rotated.
* @param maxFiles The maximum number of rotated log files to keep.
* @param rotateOnOpen If true, the log file will be rotated when opened.
* @param async If true, the sink of the new logger will be multi threaded.
* @param policy Message queue overflow policy. (Only used when async=true)
* @param async If true, Log operations will be pushed to background threads for processing,
* which can avoid blocking the main thread.
* @param policy Message queue overflow policy. (Only used when async = true)
* @return Logger handle.
* @error Logger name already exits, or maxFileSize == 0, or maxFiles > 200000.
*/
Expand All @@ -103,8 +107,9 @@ methodmap Logger < Handle
* @param minute The minute of the hour when the log file should be rotated. (0-59)
* @param truncate If true, the created file will be truncated.
* @param maxFiles If max_files > 0, retain only the last max_files and delete previous.
* @param async If true, the sink of the new logger will be multi threaded.
* @param policy Message queue overflow policy. (Only used when async=true)
* @param async If true, Log operations will be pushed to background threads for processing,
* which can avoid blocking the main thread.
* @param policy Message queue overflow policy. (Only used when async = true)
* @return Logger handle.
* @error Logger name already exits, or invalid rotation time.
*/
Expand All @@ -118,29 +123,29 @@ methodmap Logger < Handle
AsyncOverflowPolicy policy = AsyncOverflowPolicy_Block);

/**
* Get the logger name.
* Gets the logger name.
*
* @param buffer Buffer to store logger name.
* @param maxlen Maximum length of the buffer.
*/
public native void GetName(char[] buffer, int maxlen);

/**
* Get the logger log level.
* Gets the logger log level.
*
* @return The logger log level.
*/
public native LogLevel GetLevel();

/**
* Set the logger log level.
* Sets the logger log level.
*
* @param lvl Logging level enum.
* @param lvl Log level enum.
*/
public native void SetLevel(LogLevel lvl);

/**
* Set formatting for the sinks in this logger.
* Sets formatting for the sinks in the logger.
*
* @note each sink will get a new instance of a formatter object, replacing the old one.
* @note pattern flags: https://github.com/gabime/spdlog/wiki/3.-Custom-formatting#pattern-flags
Expand All @@ -151,109 +156,118 @@ methodmap Logger < Handle
public native void SetPattern(const char[] pattern, PatternTimeType type = PatternTimeType_Local);

/**
* Gets whether logging at the given log level is enabled.
* Gets whether logging is enabled for the given log level.
*
* @param lvl Logging level enum.
* @return True if logging is enabled for the given level.
* @param lvl Log level enum.
* @return True if logging is enabled for the given log level.
*/
public native bool ShouldLog(LogLevel lvl);

/**
* Logs a message.
*
* @param lvl Logging level enum.
* @param msg Logging message.
* @param lvl Log level enum.
* @param msg Log message.
*/
public native void Log(LogLevel lvl, const char[] msg);
public native void LogEx(LogLevel lvl, const char[] fmt, any ...);
public native void LogAmxTpl(LogLevel lvl, const char[] fmt, any ...);

/**
* Logs a message with the sourcepawn source code location.
*
* @param lvl Logging level enum.
* @param msg Logging message.
* @param lvl Log level enum.
* @param msg Log message.
*/
public native void LogSrc(LogLevel lvl, const char[] msg);
public native void LogSrcEx(LogLevel lvl, const char[] fmt, any ...);
public native void LogSrcAmxTpl(LogLevel lvl, const char[] fmt, any ...);

/**
* Logs a message with the source code location.
* Logs a message with the given source code location.
*
* @param file The file name of the source code location.
* @param line The line number of the source code location.
* @param func The function name of the source code location.
* @param lvl Logging level enum.
* @param msg Logging message.
* @param lvl Log level enum.
* @param msg Log message.
*/
public native void LogLoc(const char[] file, int line, const char[] func, LogLevel lvl, const char[] msg);
public native void LogLocEx(const char[] file, int line, const char[] func, LogLevel lvl, const char[] fmt, any ...);
public native void LogLocAmxTpl(const char[] file, int line, const char[] func, LogLevel lvl, const char[] fmt, any ...);

/**
* Logs a stack trace from the current function call.
* Code execution continues after the call.
*
* @param lvl Logging level enum.
* @param msg Logging message.
* @param lvl Log level enum.
* @param msg Log message.
*/
public native void LogStackTrace(LogLevel lvl, const char[] msg);
public native void LogStackTraceEx(LogLevel lvl, const char[] fmt, any ...);
public native void LogStackTraceAmxTpl(LogLevel lvl, const char[] fmt, any ...);

/**
* Aborts the current callback and throws an error.
* This function does not return in that no code is executed following it.
*
* @note The only difference from ThorwError() is that it also log the message into the logger's sinks.
*
* @param lvl Logging level enum.
* @param msg Logging message.
* @param lvl Log level enum.
* @param msg Log message.
* @error Always!
*/
public native void ThrowError(LogLevel lvl, const char[] msg);
public native void ThrowErrorEx(LogLevel lvl, const char[] fmt, any ...);
public native void ThrowErrorAmxTpl(LogLevel lvl, const char[] fmt, any ...);

public native void Trace(const char[] msg);
public native void TraceEx(const char[] fmt, any ...);
public native void TraceAmxTpl(const char[] fmt, any ...);

public native void Debug(const char[] msg);
public native void DebugEx(const char[] fmt, any ...);
public native void DebugAmxTpl(const char[] fmt, any ...);

public native void Info(const char[] msg);
public native void InfoEx(const char[] fmt, any ...);
public native void InfoAmxTpl(const char[] fmt, any ...);

public native void Warn(const char[] msg);
public native void WarnEx(const char[] fmt, any ...);
public native void WarnAmxTpl(const char[] fmt, any ...);

public native void Error(const char[] msg);
public native void ErrorEx(const char[] fmt, any ...);
public native void ErrorAmxTpl(const char[] fmt, any ...);

public native void Fatal(const char[] msg);
public native void FatalEx(const char[] fmt, any ...);
public native void FatalAmxTpl(const char[] fmt, any ...);

/**
* Manual flush logger contents.
*/
public native void Flush();

/**
* Get the minimum log level that will trigger automatic flush.
* Gets the minimum log level that will trigger automatic flush.
*
* @return the minimum log level that will trigger automatic flush.
*/
public native LogLevel GetFlushLevel();

/**
* Set the minimum log level that will trigger automatic flush.
* Sets the minimum log level that will trigger automatic flush.
*
* @note If lvl out of bounds, native will be modified to the nearest boundary.
*
* @param lvl Logging level enum.
* @param lvl Log level enum.
*/
public native void FlushOn(LogLevel lvl);

/**
* Gets whether backtrace logging is enabled.
*
* @return Return true if backtrace logging is enabled.
* @return True if backtrace logging is enabled.
*/
public native bool ShouldBacktrace();

Expand All @@ -277,28 +291,24 @@ methodmap Logger < Handle
/**
* Add a new sink to sinks.
*
* @param sink Handle of sink.
* @param sink Sink handle.
* @error Invalid sink handle.
*/
public native void AddSink(Sink sink);

/**
* Drop the reference to the given sink
* Remove a sink from the sinks.
*
* @param sink Handle of Sink.
* @return True on success, false if the sink was not found.
* @param sink Sink handle.
* @error Invalid sink handle.
*/
public native bool DropSink(Sink sink);
public native void DropSink(Sink sink);

/**
* Sets the callback when logging errors occur.
*
* @note This machine is not thread safe.
* Recommend using this native only during initialization.
* Sets the handler function for logging errors.
*
* @param callback A callback called when an error occurs.
* @error Invalid error callback.
* @param handler A handler function that is called when an error occurs.
* @error Invalid error handler function.
*/
public native void SetErrorHandler(Log4spErrorCallback callback);
public native void SetErrorHandler(LoggerErrorHandler handler);
}
10 changes: 5 additions & 5 deletions sourcemod/scripting/include/log4sp/sinks/base_file_sink.inc
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ methodmap BaseFileSink < Sink
/**
* Trivial file sink with single file as target.
*
* @param file The file path where the log messages will be written.
* @param truncate If true, the created file will be truncated.
* @param async If true, the sink will be multi threaded.
* @return Handle for a base file sink.
* @param file The file path where the log messages will be written.
* @param truncate If true, the created file will be truncated.
* @param multiThread If true, the created sink will be multi threaded and thread safe.
* @return BaseFileSink handle.
*/
public native BaseFileSink(const char[] file, bool truncate = false, bool aysnc = false);
public native BaseFileSink(const char[] file, bool truncate = false, bool multiThread = false);

/**
* Get the current filename being used by the file sink.
Expand Down
Loading

0 comments on commit c16ab81

Please sign in to comment.