[module] - Tiny module to create logfiles

Share your advanced PureBasic knowledge/code with the community.
miso
Enthusiast
Enthusiast
Posts: 466
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

[module] - Tiny module to create logfiles

Post by miso »

Nothing advanced here, though might save a little time to someone. Small enough to be adjusted to specific needs. Save example to be able to run it.

Code: Select all

;-===MODULE DESCRIPTION===
;Tiny module to create plain text logfiles
;Created with PB 6.20 Beta 1
;Author:      :miso
;Creation date:2025.01.29
;Scope        :all platform, but tested only on Windows 7 64 bit
;Permissions  :777, do what you want, (author takes no responsibilities nor any claims)
;Known Issues :Does not check permissions for parent directory (platform compatibility reasons)

EnableExplicit
;-===MODULE DECLARATION===
DeclareModule log
  ;-===CONSTANTS===
  #DirectoryType = -2
  #BufferSize    = 2048
  ;-===GLOBALS===
  ;###
  ; these globals are public, but they're not meant to be changed manually outside from the module.
  ; They're here, because that way I can use them together with modulename inside the module,
  ; and that seems a bit more clear/distinctive to my eyes (personal preference)
  ;###
  Global directory.s, filename.s
  Global filehandle.i = #False
  Global opened.i = #False
  
  ;-===PROCEDURE DECLARATIONS===
  Declare.i setdirectory(dir.s)
  Declare.i setfile(filename.s)
  Declare.i open()
  Declare.i close()
  Declare.i delete()
  Declare.i write(entry.s)
  Declare.i write_plain(entry.s)
EndDeclareModule

;-===MODULE===
Module log
  ;-===AUXILIARY PROCEDURES===
  ;***************************************
  ;auxiliary function for date
  ;***************************************
  Procedure.s sub_getdate()
    ProcedureReturn FormatDate("%yyyy-%mm-%dd %hh:%mm:%ss :: ",Date())
  EndProcedure
  
  ;-===PUBLIC PROCEDURES===
  ;***************************************
  ;Sets the directory for the logfile
  ;***************************************
  Procedure.i setdirectory(dir.s)
    If log::opened
      Debug "error, trying to set directory, but a logfile is already opened"
      ProcedureReturn #False
    EndIf
    
    If FileSize(dir.s) = #DirectoryType
      log::directory.s = dir.s
      ProcedureReturn #True
    EndIf
    Debug "Error. Trying to set invalid log directory:" + dir.s
    ProcedureReturn #False
  EndProcedure
  
  ;***************************************
  ;Sets the name of the logfile
  ;***************************************
  Procedure.i setfile(name.s)
    If name.s<>""
      log::filename.s = name.s
      ProcedureReturn #True
    EndIf
    Debug "Error. Trying to set empty string as logfile name:" + name.s
    ProcedureReturn #False
  EndProcedure
  
  ;***************************************
  ;Opens a logfile to write
  ;***************************************
  Procedure.i open()
    If log::opened Or IsFile(log::filehandle.i)
      Debug "Error, logfile is already opened"
      ProcedureReturn #False
    EndIf
    log::filehandle.i = OpenFile(#PB_Any,log::directory.s+log::filename.s,#PB_File_Append)
    If Not IsFile(log::filehandle.i)
      Debug "Error, could not open the logfile "+log::directory.s+log::filename.s
      ProcedureReturn #False
    EndIf
    log::opened.i = #True
    FileBuffersSize(log::filehandle.i,log::#BufferSize)
    ProcedureReturn #True
  EndProcedure
  
  ;***************************************
  ;closes the logfile
  ;***************************************
  Procedure.i close()
    If Not log::opened Or Not IsFile((log::filehandle.i))
      Debug "Error, trying to close logfile that is not opened."
      ProcedureReturn #False
    EndIf
    CloseFile(log::filehandle.i)
    log::filehandle.i = #False
    log::opened.i = #False
    ProcedureReturn #True
  EndProcedure
  
  ;***************************************
  ;Deletes a logfile, closing it if opened
  ;***************************************
  Procedure.i delete()
    If log::opened : log::close() : EndIf
    If FileSize(log::directory.s+log::filename.s)
      DeleteFile(log::directory.s+log::filename.s)
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
  EndProcedure
    
  
  ;***************************************
  ;Writes an entry into the opened logfile
  ;***************************************
  Procedure.i write(entry.s)
    If Not log::opened Or Not IsFile(log::filehandle.i)
      Debug "Error, trying to write logentry, but logfile is not opened"
      ProcedureReturn #False
    EndIf
    WriteStringN(log::filehandle.i,sub_getdate()+entry.s)
    FlushFileBuffers(log::filehandle.i)
    ProcedureReturn #True
  EndProcedure
  
  ;*************************************************************
  ;Writes an entry into the opened logfile without date and time
  ;*************************************************************
  Procedure.i write_plain(entry.s)
    If Not log::opened Or Not IsFile(log::filehandle.i)
      Debug "Error, trying to write log entry, but logfile is not opened"
      ProcedureReturn #False
    EndIf
    WriteStringN(log::filehandle.i,entry.s)
    FlushFileBuffers(log::filehandle.i)
    ProcedureReturn #True
  EndProcedure
EndModule



;-===EXAMPLE USAGE===
;***************************************************************
;Example usage
;***************************************************************

log::setdirectory(GetCurrentDirectory())
log::setfile("mylog.log")
;log::delete() ;uncomment this to check and delete a possible previous logfile to make the log not continous
log::open()

log::write_plain("#######################################")
log::write("Started program")
log::write("Test log entry")
log::write("Program closed")
log::close()
;log::delete() ;uncomment this line to remove the created sample logfile from your disk.
End


User avatar
Caronte3D
Addict
Addict
Posts: 1361
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: [module] - Tiny module to create logfiles

Post by Caronte3D »

Nice! Thanks for sharing! :wink:
Quin
Addict
Addict
Posts: 1132
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: [module] - Tiny module to create logfiles

Post by Quin »

Adding this to my code archive for sure, thanks :8)
infratec
Always Here
Always Here
Posts: 7613
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: [module] - Tiny module to create logfiles

Post by infratec »

I think with a continious open log file it is not possible to use tail or similar programs.
I also miss a loglevel.
infratec
Always Here
Always Here
Posts: 7613
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: [module] - Tiny module to create logfiles

Post by infratec »

I use something like this:

Logging.pbi

Code: Select all

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


Enumeration LogLevels
  #LogLevel_Emergency
  #LogLevel_Alert
  #LogLevel_Critical
  #LogLevel_Error
  #LogLevel_Warning
  #LogLevel_Notice
  #LogLevel_Informational
  #LogLevel_Debug
EndEnumeration


Global LogLevel.i   ; you can set it via program parameter at program start
LogLevel = #LogLevel_Warning

Global Dim LogLevel$(#LogLevel_Debug)
LogLevel$(#LogLevel_Emergency) = "[EMERGENCY] "
LogLevel$(#LogLevel_Alert) = "[ALERT] "
LogLevel$(#LogLevel_Critical) = "[CRITICAL] "
LogLevel$(#LogLevel_Error) = "[ERROR] "
LogLevel$(#LogLevel_Warning) = "[WARNING] "
LogLevel$(#LogLevel_Notice) = "[NOTICE] "
LogLevel$(#LogLevel_Informational) = "[INFORMATIONAL] "
LogLevel$(#LogLevel_Debug) = "[DEBUG] "

Global LogFilename$ ; you can set it to what ever you want at program start
CompilerIf #PB_Compiler_Debugger
  LogFilename$ = GetHomeDirectory() + GetFilePart(ProgramFilename(), #PB_FileSystem_NoExtension) + ".log"
CompilerElse
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      LogFilename$ = "/var/log/" + GetFilePart(ProgramFilename()) + ".log"
    CompilerCase #PB_OS_MacOS
      LogFilename$ = GetHomeDirectory() + "Library/Logs/" + GetFilePart(ProgramFilename(), #PB_FileSystem_NoExtension) + ".log"
    CompilerCase #PB_OS_Windows
      LogFilename$ = GetPathPart(ProgramFilename()) + GetFilePart(ProgramFilename(), #PB_FileSystem_NoExtension) + ".log"
  CompilerEndSelect
CompilerEndIf
  
CompilerIf #PB_Compiler_Thread
  Global LogMutex.i   ; needed to be thread safe
  LogMutex = CreateMutex()
CompilerEndIf


Procedure Logging(Text$, Level.i=#LogLevel_Warning)
  
  Protected File.i
  
  
  Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss ", Date()) + LogLevel$(Level) + Text$
  If Level <= LogLevel
    
    CompilerIf #PB_Compiler_Thread
      LockMutex(LogMutex)
    CompilerEndIf
    
    File = OpenFile(#PB_Any, LogFilename$, #PB_File_Append)
    If File
      WriteStringN(File, FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss ", Date()) + LogLevel$(Level) + Text$)
      CloseFile(File)
    EndIf
    
    CompilerIf #PB_Compiler_Thread
      UnlockMutex(LogMutex)
    CompilerEndIf
    
  EndIf
  
EndProcedure



CompilerIf #PB_Compiler_IsMainFile
  
  ;LogLevel = #LogLevel_Debug
  ;LogFilename$ = "c:\tmp\logging.log"
  
  Logging("Started", #LogLevel_Notice)
  
  Logging("Warning test")
  
  Logging("Finished", #LogLevel_Notice)
  
CompilerEndIf
Last edited by infratec on Thu Jan 30, 2025 12:54 pm, edited 4 times in total.
miso
Enthusiast
Enthusiast
Posts: 466
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

Re: [module] - Tiny module to create logfiles

Post by miso »

@Infratec
I wanted something that has an output very similar to ogre log. The tail is just in the example, log level can be written together with log entry if required.
(might be changed to create html with red colored warnings) It's up to the developer how to use the module or what kind of warning level is needed. It's a barebone skeleton that can be adjusted.

(Your solution is nice and valid though, I'm not arguing)
infratec
Always Here
Always Here
Posts: 7613
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: [module] - Tiny module to create logfiles

Post by infratec »

And for real heavy logging multithreaded programs I wrote a logging pbi which places the entries in a list
which is written to disk in an own thread.

Else it was not possible to ensure the order of the log entries in a multithreaded program which uses an external lib with a logging callback.
Post Reply