User Tools

Site Tools


19.5 Logging

The gb.logging component implements a flexible system for logging Gambas applications. This component provides its functionality through the two classes Formatter and Logger.

  • The Formatter class provides a good way for efficient debugging in the testing phase of a programme.
  • You can achieve the complete log functionality by using the class Logger (Logger object).
  • The formatting of the log texts is based on the document RFC 5424, which describes the standard format (→ for system log files (syslog).

19.5.1 Class Formatter

The class Formatter (gb.logging) can be used like a function. This class formats a line to automatically replace the required logging data. You will find which format tags you can use in section

In the Formatter class you can not - until Gambas 3.5.3 - use these four 4 format tags:

  $(callLocation); $(callFile); $(callLine) und $(callFunction)


The following statement in the source code determines on the one hand the log text and on the other hand the output format as well as the log level assigned to the log text (→ section Level constants and (Level property)):

It produces the following output in the Gambas IDE at runtime:

  [18:59:04.227] - Test-Mitteilung - WARNING

You can insert the above statement (*) with your special protocol texts at different places in the source code. You can also use the following statement from the 'Error Management' section with the same effect:

  Debug "[" & Format(Time(), "hh:nn:ss.uu") & "]" & " - Test-Mitteilung" & " - WARNUNG"

which writes the following output to the console of the IDE, which also contains information about the file, the event and the line in the source code:

  FMain.btnDebug_Click.11: [18:59:04.227] - Test-Mitteilung - WARNUNG

19.5.2 Class Logger

The Logger (gb.logging) class provides, among other things, basic mechanisms for sending log texts. You can create as many logger objects as you need, because the gb.logging component is excellent for managing multiple logs for different log levels, for example.

The Logger class has the following features introduced in the next section.

  • five constants,
  • two properties and
  • one method. Constants

ConstantNumeric valueDescription
Critical0The level constant defines a protocol text as a critical message.
Error1The level constant defines a protocol text as an error message.
Warning2The level constant defines a protocol text as a warning.
Info3The level constant defines a protocol text as an information message.
Debug4The level constant defines a protocol text as debug message.

Table Overview of the level constants of the class Logger Properties

FormatString*Sets or returns the format for the log texts (logger object).
LevelInteger3Sets or returns the minimum log level for a logger object. The values of Level are in the interval from 0 to 4 → constants.

Table Properties of the class Logger

The default * format of the Logger class is:

  [$(now)] [$(levelname)] [$(callLocation)] $(message)

and only needs to be redefined by you (→ Table if you want to set a different log text format.

Notes on the format:

A format string describes via the tags $(..) which information at which position is included in the protocol text:

Note the notation of the above tags in the format string (→ case-sensitive) !For the level property, insert either the constants or their numeric values, giving preference to the constants.You can also insert your own text or individual characters in the format string. Method

The Logger class has only the Logger.isEnabledFor(..) method:

The function returns True if, for example, the active Logger object 'MyLog' has been enabled for the log level specified by 'iLevel'.

To demonstrate the function, you can use this source code to check how much and which log levels are active for 'MyLog':

  MyLog.Level = Logger.Error
  If MyLog.isEnabledFor(Logger.Critical) Then Print "Critical-Level aktiv!"
  If MyLog.isEnabledFor(Logger.Error) Then Print "Error-Level aktiv!"
  If MyLog.isEnabledFor(Logger.Warning) Then Print "Warning-Level aktiv!"
  If MyLog.isEnabledFor(Logger.Info) Then Print "Info-Level aktiv!" ' Default: Logger.Info (=3)
  If MyLog.isEnabledFor(Logger.Debug) Then Print "Debug-Level aktiv"

The console display shows the following two levels because with 'MyLog.Level = Logger.Error' only the log levels ≤ Logger.Error are active:

  Critical-Level aktiv!
  Error-Level aktiv! Logger object

You can create a logger object like this:

  Public hLogger = Logger
  hLogger = Logger ( [ iMinLevel As Integer, sOutput As String ] )


(a) Logger object with the default level (=Logger.Info) to display the log texts in the console of the IDE.
(b) Logger object with a self-defined level (0..4) for displaying the log texts in the console of the IDE.
(c) Logger object with a self-defined level (0..4) and storage of the log texts in a log file in a directory in which the user also has write access.

  (a)	hLogger As New Logger	' Logger-Level » Info
  (b)	hLogger As New Logger(2) 	' Logger-Level » Warning
  (c)  	hLogger As New Logger(Logger.Error, Lower(User.Home &/ Application.Name & ".log")) Logging

For an object of the Logger class - for example named 'MyLog':

  Sub MyLog ( sMessage As String [ , iLevel As Integer ] )

with the two parameters:

  • sMessage is the text that is output after the specified formatting and.
  • iLevel determines the log level (→ Table and is an optional parameter,

to generate a log text for the active logger object 'MyLog'.

With the help of the procedure MyLog(..) and the use of a Logger object with its constants, properties as well as the method isEnabledFor(..) with 'Function isEnabledFor ( iLevel As Integer ) As Boolean' a flexible log system for a Gambas programme can be realised.

19.5.3 Example

Just as with the Formatter class, you can also use the Logger class to send log texts to the standard output (→ console) and display them there.

For the development and testing of Gambas programmes, it is quite advantageous to save the log texts in a log file (→ variant (c)).

Here is a source code excerpt according to variant ©:

[1] Public MyLog As Logger
[2] Public FilePath As String = Lower(User.Home &/ Application.Name & ".log")
[3] Public bAppendMode As Boolean = True ' True → Log-Datei fortschreiben
[5] Public Sub Form_Open()
[6]   FMain.Center
[7]   FMain.Resizable = False
[8][9] ' Minimales Log-Level, Log-Dateipfad und Modus festlegen
[10]   If Exist(FilePath) Then
[11]      If bAppendMode = False Then
[12]         Try Kill FilePath
[13]         Wait
[14]         MyLog = New Logger(Logger.Error, FilePath)
[15]      Endif ' bAppendMode = False ?
[16]   Endif ' Exist(FilePath) ?
[17]   MyLog = New Logger(Logger.Error, FilePath)
[19] ' Log-Format festlegen
[20]   MyLog.Format = "$(message)"
[21] ' Log-Text ausgeben
[22]   If bAppendMode = True And Exist(FilePath) Then MyLog("", MyLog.Level) ' Leerzeile einfügen
[24]   MyLog.Format = "$(message)"
[25]   MyLog(Format(Now, "dddd - dd. mmmm yyyy"), MyLog.Level)
[27]   MyLog.Format = "$(time)" & gb.Tab & "$(message)" & " mit Log-Level " & " ≤ " & " $(levelname)"
[28]   MyLog("LOG-NEUSTART", MyLog.Level)
[30]   MyLog.Format = "$(message)"
[31]   MyLog("---------------------------------------------------", MyLog.Level)
[33] ' Log-Format für alle weiteren Protokoll-Texte festlegen
[34]   MyLog.Format = "$(time)" & gb.Tab & "[$(levelname)] [$(callLocation)]" & " →  " & "$(message)"
[36] End

Now you can log further log texts in the log file at the appropriate, often critical points in the source text with modified instructions:

  MyLog("Eingabefehler Z1", Logger.Warning)   		  or
  MyLog("Eingabe-String = " & sInput, Logger.Error)   	  or
  MyLog("Division durch Null!", Logger.Critical)		  or

  MyLog.Level = Logger.Info
  MyLog("Änderung Log-Level auf " & MyLog.Level, MyLog.Level)

Here you can see a log file extract in 'Append' mode with different log levels:

  Samstag - 18. Januar 2014
  15:21:50.803	LOG-NEUSTART mit Log-Level ≤ WARNING

  15:21:54.12	[CRITICAL] [FMain.IsComplex.339] →  Eingabe-String = 3-4i,,
  15:21:55.228	[WARNING] [FMain.btnAddieren_Click.139] →  Eingabefehler Z1 oder Z2
  15:21:57.9	[ERROR] [FMain.btnConvert_Click.96] →  Eingabefehler Z1
  15:21:59.719	[CRITICAL] [FMain.IsComplex.339] →  Eingabe-String = 3-4i,,

  Samstag - 18. Januar 2014
  15:41:07.429	LOG-NEUSTART mit Log-Level ≤ ERROR

  15:41:14.908	[ERROR] [FMain.btnConvert_Click.96] →  Eingabefehler Z1
  15:41:16.282	[CRITICAL] [FMain.IsComplex.339] →  Eingabe-String = 3-4i,
  15:41:17.684	[ERROR] [FMain.btnIsComplex_Click.122] →  Eingabefehler Z1


  • Note that only those log texts are included in the log file where the specified log level is less than or equal to the current log level!
  • Log texts with a larger log level are then ignored. If the log level is less than or equal to Logger.Error, for example - as in the second section in the log file excerpt above - only error messages and critical messages are logged.
  • If you do not specify a log level, the default log level Logger.Info with the numerical value 3 is set as the log level.

You may want to limit the size of the log file if you want to continuously add to the log. An acceptable procedure is to delete the oldest log entry when a new one is added after a certain file size. Or, after a certain file size, you create an archive from the current log file and create a new log file.

19.5.4 Excursus

The Excursus section introduces you to two log variants, both of which have their own special aspects.

  • Variant 1 offers the possibility to output and display log texts either immediately in the console and/or as a message in a separate window. As a special feature, all protocol texts are kept in memory at the runtime of the programme (collection) and could only be permanently stored in a log file at the end of the programme.
  • Variant 2 is designed in such a way that every log text is immediately saved in a log file and thus offers a small advantage over variant 1 when testing a programme. Variant 1

The following source code implements the specifications of variant 1 in a module 'MyLog' - but without storing it in a log file:

  ' Gambas module file - Autor: Caveat -
  PRIVATE iDebugMode AS Integer
  PRIVATE iLogIndex AS Integer
  PRIVATE cLogLines AS Collection
  Public Sub SetDebugMode(iNewMode As Integer)
    iDebugMode = iNewMode
  Public Sub LogMessage(sMessage As String, bShowAsError As Boolean)
    If iDebugMode = NO_DEBUG Then Return
    If cLogLines = Null Then
       cLogLines = New Collection
'-- cLogLines = Null
    cLogLines.Add(sMessage, Str(iLogIndex))
    Inc iLogIndex
    If iDebugMode = DEBUG_LOG_AND_PRINT Then
       Print sMessage
    Else If iDebugMode = DEBUG_MESSAGE_LOG_AND_PRINT Then
       Print sMessage
    Endif ' iDebugMode = DEBUG_LOG_AND_PRINT
    If bShowAsError Then Message.Error(sMessage)' Zusätzliche Anzeige – aber nur bei Fehlern!
  Public Sub DisplayLogLines()
    Dim sLogLine As String
    If cLogLines = Null Then Return
    For Each sLogLine In cLogLines
      Print cLogLines.Key & ". " & sLogLine

You determine whether you want to see the log text only in the console or also as text in a separate message window with the procedure SetDebugMode(..) using the defined constants.

In the main programme, you call up protocol texts like this, for example:

MyLogger.SetDebugMode(1) ' DEBUG_LOG_ONLY
  Dim hFile As File
  Dim FilePath As String
  FilePath = "/home/hans/Bilder" &/ "gambas.png"
  Try hFile = Open FilePath For Read
  If Error Then
     MyLogger.LogMessage("Datei-Pfad: " & FilePath, True)
     MyLogger.LogMessage("Fehler: " & Error.Text & " @ " & Error.Where, False)

The output of the log content via DisplayLogLines() shows for the above source text excerpt:

1. Datei-Pfad: /home/hans/Bilder/gambas.png
2. Fehler: Unable to load image @ Stock.LoadIcon.444 Variant 2

In variant 2, selected programme outputs - in this case temperature values - are read out at fixed time intervals and logged in a log file. This is done by the specified timer procedure MyTimer_Timer() from MyTimer. Each time the programme is restarted, you can decide whether the existing log file should be deleted or the log should be updated. Alternatively, you can also use a checkbox to specify this decision in the start procedure.

The source code is clear and is given in relevant excerpts:

  Private MyTimer As Timer
  Public Sub Form_Open()
    MyTimer = New Timer As "MyTimer"
    MyTimer.Delay = 1000 * 120 ' Intervall der Datenspeicherung (→ 2 Minuten)
'-- Einbau in eine Start-Prozedur:
    If Exist(Application.Path &/ "rs232log.txt") Then
       If Message.Question("Letztes Mess-Protokoll löschen?", "Ja - löschen!", "Nein!") = 1 Then
          Try Kill Application.Path &/ "rs232log.txt"
    AddTextToFile("DATUM:  " & Format(Now, "dd. mmmm yyyy"))
  Public Sub MyTimer_Timer()
    If RS232.Status = Net.Active Then
       AddTextToFile(">  " & Format(Now, "hh:nn:ss") & "  |  " & "T = " & Asc(sTemperatureValue) & " °C")
    Endif ' RS232.Status = Net.Active ?
  Public Sub AddTextToFile(Text As String)
    Dim hFile As File
    Dim FilePath As String
    FilePath = Application.Path &/ "rs232log.txt"
    Try hFile = Open FilePath For Append
    If Error Then
    Print #hFile, Text
    Close #hFile

Here is an extract from a log file:

  DATUM:  17. Januar 2014
  >  09:47:56  |  T = 22 °C
  >  09:49:56  |  T = 24 °C
  >  09:51:56  |  T = 26 °C
  >  09:53:56  |  T = 28 °C

Of course, you can also log RS232 interface parameters or error messages in the log file.




The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k19/k19.5/start.txt · Last modified: 14.10.2023 by emma

Page Tools