B4J Question Non-UI - best way to write logs

Alexander Stolte

Expert
Licensed User
Longtime User
Every day parts of my jServer are not responding or have an internal server error and to find out what it is, I want to write logs.
Is there already a ready solution for this?
 

AHilton

Active Member
Licensed User
Longtime User
One of the first things in my Main.AppStart ...

B4X:
    #If RELEASE
        ' Anything that would normally show in the console (log(), errors, etc.) will go to this file so that I can see what's going on later
        Utils.RedirectOutputToFile(File.DirApp & DirectorySeparator & "logs", "logs.txt")
    #End If


In my Utilities Module ...

B4X:
' Redirects Output to a file
' Usage: RedirectOutput(File.DirApp, "logs.txt")
Sub RedirectOutputToFile (Dir As String, FileName As String)
    #if RELEASE
        Dim out As OutputStream = File.OpenOutput(Dir, FileName, True) 'Set to True to append the logs
        Dim ps As JavaObject
        ps.InitializeNewInstance("java.io.PrintStream", Array(out, True, "utf8"))
        Dim jo As JavaObject
        jo.InitializeStatic("java.lang.System")
        jo.RunMethod("setOut", Array(ps))
        jo.RunMethod("setErr", Array(ps))
    #end if
End Sub
' Redirects Output back to the (standard) screen
Sub RedirectOutputToScreen (Dir As String, FileName As String)
    #if RELEASE
        Dim out As OutputStream = File.OpenOutput(Dir, FileName, False) 'Set to True to append the logs
        Dim ps As JavaObject
        ps.InitializeNewInstance("java.io.PrintStream", Array(out, True, "utf8"))
        Dim fd As JavaObject
        fd.InitializeStatic("java.io.FileDescriptor")
        Dim jout As JavaObject
        jout.InitializeNewInstance("java.io.FileOutputStream", Array(fd.GetField("out")))
        ps.InitializeNewInstance("java.io.PrintStream", Array(jout, True, "utf8"))

        Dim jo As JavaObject
        jo.InitializeStatic("java.lang.System")
        jo.RunMethod("setOut", Array(ps))
        jo.RunMethod("setErr", Array(ps))
    #end if
End Sub
 
Upvote 0

Alexander Stolte

Expert
Licensed User
Longtime User
Thank you.

Together with this:
B4X:
'Logging Level: Error
Public Sub Error(module As String,Message As String)
    Log(DateTime.Date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & " " & "ERROR" & " - [" & module & "] " & Message)
End Sub

'Logging Level: Info
Public Sub Info(module As String,Message As String)
    Log(DateTime.Date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & " " & "INFO" & " - [" & module & "] " & Message)
End Sub

'Logging Level: Warning
Public Sub Warning(module As String,Message As String)
    Log(DateTime.Date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & " " & "WARNING" & " - [" & module & "] " & Message)
End Sub
Usage:
cm_functions.Info("Main","API is running")
'07/30/2020 18:13:18 INFO - [Main] API is running
It's more powerful, this is like log4net in .NET
 
Upvote 0

AHilton

Active Member
Licensed User
Longtime User
Sure, I use a reporting class, too. It allows reporting levels somewhat like yours above; reporting to various places (standard log, database, files with or without what I posted above, email, sms, and a reporting server); etc.

The nice thing about what I posted above, is that it'll log everything ... whether you use the log() command or your cm_functions subs or not. The bad thing is that it logs *everything* whether you want it or not.
 
Upvote 0

tchart

Well-Known Member
Licensed User
Longtime User
I wrote a code module called Logger.

In my main I specify the log level in the AppStart

B4X:
    'FILE|ALL|DEBUG|INFO|WARN|OFF
    If log_level.ToUpperCase = "FILE"  Then Logger.Level = 99
    If log_level.ToUpperCase = "ALL"   Then Logger.Level = 9
    If log_level.ToUpperCase = "DEBUG" Then Logger.Level = 3
    If log_level.ToUpperCase = "INFO"  Then Logger.Level = 2
    If log_level.ToUpperCase = "WARN"  Then Logger.Level = 1
    If log_level.ToUpperCase = "OFF"   Then Logger.Level = 0
    
    #if DEBUG
        Logger.Level = 9
    #End If

Then instead of going Log() I just use it like this;

Logger.Info("Some information")
Logger.Error("An Error Occured")

B4X:
#IgnoreWarnings: 9,12

Sub Process_Globals
    Dim Level As Int
    'FILE|ALL|DEBUG|INFO|WARN|OFF
    '99  |9  |3    |2   |1   |0
End Sub

Sub Warn(Message As String)
    If Level >= 1 Then Log(GetTimeStamp & ":WARN:" & Message)
    If Level == 99 Then WriteTextLog(GetTimeStamp & ":WARN:" & Message)
End Sub

Sub Info(Message As String)
    If Level >= 2 Then Log(GetTimeStamp & ":INFO:" & Message)
    If Level == 99 Then WriteTextLog(GetTimeStamp & ":INFO:" & Message)
End Sub

Sub Debug(Message As String)
    If Level >= 3 Then Log(GetTimeStamp & ":DEBUG:" & Message)
    If Level == 99 Then WriteTextLog(GetTimeStamp & ":INFO:" & Message)
End Sub

Sub Error(Message As String)
    Log(GetTimeStamp & ":ERROR:" & Message)
    'If Level == 99 Then
    WriteTextLog(GetTimeStamp & ":ERROR:" & Message)
    'End If
End Sub

Sub WriteTextLog(Message As String)
    Dim Writer As TextWriter
    Writer.Initialize(File.OpenOutput(File.DirApp, "Logger.txt", True))
    Writer.WriteLine(GetTimeStamp & ":" & Message)
    Writer.Flush
    Writer.Close
End Sub

Sub DumpToFile(Message As String)
    File.WriteString(File.DirApp,GetTimeStamp.Replace(":","").Replace(" ","") & ".txt",Message)
End Sub

Sub GetTimeStamp As String
    '2018-09-28 06:47:27.723:INFO:oejs.Server:main: Started @1723ms'
    Dim df As String = DateTime.DateFormat
    Dim Output As String   
    DateTime.DateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
    Output = DateTime.date(DateTime.Now)   
    DateTime.DateFormat=df   
    Return Output   
End Sub
 
Upvote 0
Top