lhs_lib/SYS/lhs_log_ext.pbi

343 lines
9.7 KiB
Plaintext

;**************************************
;*
;* lhs_log_ext.pbi
;*
;* Multi Logfile thread logger.
;*
;* For single logthread use lhs_log.pbi
;*
;* (c) by René Linder
;* (c) by Linder Hard- und Software
;*
;* Lizenz LGPL V2.1
;{ Short Documentation:
;*
;* lhs_log_ext::App_Name = "Test App"
;* LogUUID.s = lhs_log_ext::Create("TestLog")
;* lhs_log_ext::SetLogFile(LogUUID,"test_app.log"))
;* lhs_log_ext::SetMaxSize(LogUUID,32)
;* lhs_log_ext::SetLogLevel(LogUUID,lhs_log_ext::#Error)
;* lhs_log_ext::SetLogDateFormat(LogUUID,"%yyyy.%mm.%dd %hh:%ii:%ss")
;* lhs_log_ext::SetLogFileDateFormat(LogUUID,"%yyyy_%mm_%dd_%hh_%ii_%ss")
;* lhs_log_ext::Init(LogUUID,)
;* lhs_log_ext::Out(LogUUID,"Log started.", #lhs_log_ext::#Debug)
;* lhs_log_ext::OutL(LogUUID,lhs_log_ext::#Info, "Info Level")
;* lhs_log_ext::Close(LogUUID)
;* lhs_log_ext::StopAllLogger()
;}
CompilerIf #PB_Compiler_Thread <> 1
CompilerError "Muss Threadsafe Kompiliert werden"
;Need to be compiled threadsafe
CompilerEndIf
DeclareModule lhs_log_ext
Global.s App_Name = "lhs_ext_Logger"
#Debug = #True
#NoDebug = #False
#Console = #True
#NoConsole = #False
Structure LogThreads
Logger_UUID.s
Logger_Name.s
Thread.i
FileID.i
LogFile.s
Mutex.i
WorkerSemaphore.i
ExitSemaphore.i
Exit.i
MaxSize.q
LastSize.q
LogLevel.i
LogFileDateFormat.s
LogDateFormat.s
debugger.i
console.i
List Messages.s()
EndStructure
Global NewMap Logger.LogThreads()
Global NewList LoggerUUID.s()
Enumeration LogLevel
#NoLog
#Error
#Warning
#Info
#Debugging
EndEnumeration
Declare IsCreated(UUID.s)
Declare SetLogFile(UUID.s, LogFileName.s)
Declare SetMaxSize(UUID.s, Megabyte.i)
Declare SetLogLevel(UUID.s, Level.i)
Declare SetLogFileDateFormat(UUID.s, DateFormat.s)
Declare SetLogDateFormat(UUID.s, DateFormat.s)
Declare.s Create(Name.s)
Declare Init(UUID.s)
Declare Out(UUID.s, ToLog.s, debugger.i = #NoDebug)
Declare OutL(UUID.s, LogType.i, ToLog.s, debugger.i = #NoDebug)
Declare Close(UUID.s)
Declare StopAllLogger()
EndDeclareModule
Module lhs_log_ext
IncludeFile "lhs_uuid.pbi"
Global CreateLoggerMutex.i = CreateMutex()
Global ConsoleMutex.i = CreateMutex()
Procedure.s Create(Name.s)
Define.s InternalUUID
If Len(Name) > 0 And TryLockMutex(CreateLoggerMutex)
InternalUUID = CreateUUID()
AddElement(LoggerUUID())
LoggerUUID() = InternalUUID
Logger(InternalUUID)\Logger_UUID = InternalUUID
Logger(InternalUUID)\Logger_Name = Name
Logger(InternalUUID)\LastSize = 0
Logger(InternalUUID)\Exit.i = 0
Logger(InternalUUID)\Mutex = CreateMutex()
Logger(InternalUUID)\WorkerSemaphore = CreateSemaphore()
Logger(InternalUUID)\ExitSemaphore = CreateSemaphore()
Logger(InternalUUID)\MaxSize.q = 32 * 1024 * 1024
Logger(InternalUUID)\LastSize.q = 0
Logger(InternalUUID)\LogLevel.i = #Debugging
Logger(InternalUUID)\LogFileDateFormat.s = "%yyyy_%mm_%dd_%hh_%ii_%ss"
Logger(InternalUUID)\LogDateFormat.s = "%yyyy.%mm.%dd %hh:%ii:%ss"
Logger(InternalUUID)\console = #NoConsole
UnlockMutex(CreateLoggerMutex)
ProcedureReturn InternalUUID
EndIf
EndProcedure
Procedure IsCreated(UUID.s)
If FindMapElement(Logger(), UUID)
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure StopAllLogger()
LockMutex(CreateLoggerMutex)
ResetList(LoggerUUID())
While NextElement(LoggerUUID())
Close(LoggerUUID())
Wend
ClearList(LoggerUUID())
If MapSize(Logger()) = 0
UnlockMutex(CreateLoggerMutex)
Else
ResetMap(Logger())
While NextMapElement(Logger())
If IsThread(Logger()\Thread)
Close(Logger()\Logger_UUID)
Else
DeleteMapElement(Logger())
EndIf
Wend
EndIf
EndProcedure
Procedure SetMaxSize(UUID.s, Megabyte.i)
If IsCreated(UUID)
If Megabyte > 0 And Megabyte < 1025
Logger(UUID)\MaxSize = Megabyte * 1024 * 1024
Else
Logger(UUID)\MaxSize = 32 * 1024 * 1024
EndIf
EndIf
EndProcedure
Procedure SetLogLevel(UUID.s, Level.i)
If IsCreated(UUID)
Select Level
Case #Info
Logger(UUID)\LogLevel = #Info
Case #Warning
Logger(UUID)\LogLevel = #Warning
Case #Error
Logger(UUID)\LogLevel = #Error
Case #Debug
Logger(UUID)\LogLevel = #Debugging
Default
Logger(UUID)\LogLevel = #Debugging
EndSelect
EndIf
EndProcedure
Procedure SetLogFile(UUID.s, LogFileName.s)
Protected.i TestFile_ID
If IsCreated(UUID)
TestFile_ID = OpenFile(#PB_Any, LogFileName, #PB_File_Append | #PB_File_NoBuffering)
If IsFile(TestFile_ID)
Logger(UUID)\LogFile = LogFileName
CloseFile(TestFile_ID)
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndIf
EndProcedure
Procedure SetLogFileDateFormat(UUID.s, DateFormat.s)
If IsCreated(UUID)
If Len(DateFormat)>4
Logger(UUID)\LogFileDateFormat = DateFormat
EndIf
EndIf
EndProcedure
Procedure SetLogDateFormat(UUID.s, DateFormat.s)
If IsCreated(UUID)
If Len(DateFormat)>4
Logger(UUID)\LogDateFormat = DateFormat
EndIf
EndIf
EndProcedure
Procedure CheckMaxSize(UUID.s)
If IsCreated(UUID)
If Logger(UUID)\LastSize = 0
Logger(UUID)\LastSize = FileSize(Logger(UUID)\LogFile)
EndIf
ProcedureReturn Bool(Logger(UUID)\LastSize < Logger(UUID)\MaxSize)
EndIf
EndProcedure
Procedure UpdateLastSizeString(UUID.s, String.s)
If IsCreated(UUID)
Logger(UUID)\LastSize + StringByteLength(String.s)
EndIf
EndProcedure
Procedure LogThread(UUID_Address)
Protected MyUUID.s = PeekS(UUID_Address)
Protected File_ID
Define ToWrite.s
SignalSemaphore(Logger(MyUUID)\ExitSemaphore)
WaitSemaphore(Logger(MyUUID)\WorkerSemaphore)
File_ID = OpenFile(#PB_Any, Logger(MyUUID)\LogFile, #PB_File_Append | #PB_File_NoBuffering)
If IsFile(File_ID)
Repeat
WaitSemaphore(Logger(MyUUID)\WorkerSemaphore)
If Logger(MyUUID)\Exit = 1
LockMutex(Logger(MyUUID)\Mutex)
If ListSize(Logger(MyUUID)\Messages()) > 0
Repeat
FirstElement(Logger(MyUUID)\Messages())
ToWrite = FormatDate(Logger(MyUUID)\LogDateFormat, Date()) + " - " + Logger(MyUUID)\Messages()
UpdateLastSizeString(MyUUID, ToWrite):WriteStringN(File_ID, ToWrite)
DeleteElement(Logger(MyUUID)\Messages())
Until ListSize(Logger(MyUUID)\Messages()) = 0
EndIf
CloseFile(File_ID)
UnlockMutex(Logger(MyUUID)\Mutex)
Break
Else
LockMutex(Logger(MyUUID)\Mutex)
FirstElement(Logger(MyUUID)\Messages())
ToWrite = FormatDate(Logger(MyUUID)\LogDateFormat, Date()) + " - " + Logger(MyUUID)\Messages()
UpdateLastSizeString(MyUUID, ToWrite)
If Not CheckMaxSize(MyUUID)
CloseFile(File_ID)
If CopyFile(Logger(MyUUID)\LogFile, Logger(MyUUID)\LogFile+FormatDate(Logger(MyUUID)\LogFileDateFormat, Date()))
DeleteFile(Logger(MyUUID)\LogFile)
EndIf
File_ID = OpenFile(#PB_Any, Logger(MyUUID)\LogFile, #PB_File_Append | #PB_File_NoBuffering)
EndIf
WriteStringN(File_ID, ToWrite)
DeleteElement(Logger(MyUUID)\Messages())
UnlockMutex(Logger(MyUUID)\Mutex)
EndIf
ForEver
SignalSemaphore(Logger(MyUUID)\ExitSemaphore)
EndIf
EndProcedure
Procedure Init(UUID.s)
If IsCreated(UUID)
File_ID = OpenFile(#PB_Any, Logger(UUID)\LogFile, #PB_File_Append | #PB_File_NoBuffering)
If IsFile(File_ID)
CloseFile(File_ID)
Else
ProcedureReturn #False
EndIf
CreateThread(@LogThread(), @UUID)
WaitSemaphore(Logger(UUID)\ExitSemaphore)
SignalSemaphore(Logger(UUID)\WorkerSemaphore)
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure OutPutConsole(ToLog.s)
;Hardlock ConsoleOutput
If LockMutex(ConsoleMutex)
PrintN(ToLog)
UnlockMutex(ConsoleMutex)
EndIf
EndProcedure
Procedure Out(UUID.s, ToLog.s, debugger.i = #NoDebug)
If IsCreated(UUID)
LockMutex(Logger(UUID)\Mutex)
LastElement(Logger(UUID)\Messages())
AddElement(Logger(UUID)\Messages())
Logger(UUID)\Messages() = ToLog
If Logger(UUID)\debugger = #Debug
Debug ToLog
EndIf
If Logger(UUID)\console = #Console
OutPutConsole(ToLog)
EndIf
UnlockMutex(Logger(UUID)\Mutex)
SignalSemaphore(Logger(UUID)\WorkerSemaphore)
EndIf
EndProcedure
Procedure OutL(UUID.s, LogType.i, ToLog.s, debugger.i = #NoDebug)
If IsCreated(UUID)
If debugger = #Debug
LogType = #Debugging
EndIf
If LogType <= Logger(UUID)\LogLevel Or debugger = #Debug
Select LogType
Case #Info
ToLog = "Info: " + ToLog
Case #Warning
ToLog = "Warning: " + ToLog
Case #Error
ToLog = "Error: " + ToLog
Case #Debugging
ToLog = "Debug: " + ToLog
Default
ToLog = "Debug: " + ToLog
EndSelect
Out(UUID, ToLog, debugger)
ProcedureReturn #True
EndIf
EndIf
EndProcedure
Procedure Close(UUID.s)
If IsCreated(UUID)
Logger(UUID)\Exit=1
SignalSemaphore(Logger(UUID)\WorkerSemaphore)
WaitSemaphore(Logger(UUID)\ExitSemaphore)
DeleteMapElement(Logger(), UUID)
EndIf
EndProcedure
EndModule