B4J Question [SOLVED] Getting jServer logs and show it on the IDE logs.

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

as for the thread title, I'm in a situation where I start the server and need to show any request in the app log.

I have 3 questions related to this...

(Question 1)
Logs should be visualized on the IDE logs for developing purposes (this is part of a library), but when
the final app is compiled and started with a .bat file (that open prompt on Windows or someelse in terminal on Linux)
logs should visualized here as usually.

I have to get it as fast possible, the only way I found now is to use a Timer (set to 100 milliseconds),
every timer tick open a log file, read it as string and get modifications from last read. This is really not elegant way, it open read and close
the server log file 10 times every second.

Someone know a better way to do this ?
Is there a better way to redirect the server logs ?

Here is my actually code, it works and show on the IDE log every request, but it open a file a lots of times.
B4X:
Log("Start http server on port " & Port)
 
Server.Initialize("Server")
Server.Port = Port
Server.StaticFilesFolder = mRootDir
Server.LogsFileFolder = File.Combine(File.DirData("B4XWebGL"), "logs")
Server.LogsRetainDays = 1
Server.LogFormat = $"%{client}a %u %{dd/MM/yyyy HH:mm:ss ZZZ|GMT+2:00}t  [%s]  %r  (%O Bytes)      SOURCE: %{Referer}i :: %{User-Agent}i"$
Server.AddHandler("/MainPage", "MyPageHandler", False) ' Handle main page
Server.Start
    
TimerRequestsLog.Initialize("TimerRequestsLog", 100)
TimerRequestsLog.Enabled = True
Log($"Server started"$)

Private Sub TimerRequestsLog_Tick
    Try
        If mLogOldDate <> DateTime.Date(DateTime.Now) Then
            mLogsFileFolder = Server.LogsFileFolder
            mLogsFileName = "b4j-" & DateTime.Date(DateTime.Now) & ".request.log"
 
            If File.Exists(mLogsFileFolder, mLogsFileName) = False Then
 
                Dim dayAfter As String = "b4j-" & DateTime.Date(DateTime.Now + DateTime.TicksPerDay) & ".request.log"
                Dim dayBefore As String = "b4j-" & DateTime.Date(DateTime.Now - DateTime.TicksPerDay) & ".request.log"
'                Log(dayAfter)
'                Log(dayBefore)
 
                If File.Exists(mLogsFileFolder, dayAfter) Then
                    mLogsFileName = dayAfter
                Else if File.Exists(mLogsFileFolder, dayBefore) Then
                    mLogsFileName = dayBefore
                Else
                    LogErr("The server log file do not exist in " & mLogsFileFolder)
                    return
                End If
            End If
 
            Log("Server Log file name: " & mLogsFileName)
            Log("Server Log file path: " & File.Combine(mLogsFileFolder, mLogsFileName))
 
            mLogOldDate = DateTime.Date(DateTime.Now)
 
            old = File.ReadString(mLogsFileFolder, mLogsFileName)
 
            If old.Length > 0 Then
                Log(" ") : Log("INITIAL FILE LOG:")
                Log(old)
                Log("END OF INITIAL FILE LOG") : Log(" ")
            Else
                Log("Server Log File actually do not contain logs")
            End If
        End If
 
        If File.Exists(mLogsFileFolder, mLogsFileName) = False Then Return
        new = File.ReadString(mLogsFileFolder, mLogsFileName)
 
'    If new.Length <> old.Length Then
'        LogString = new.SubString(old.Length)
'        LogColor(LogString, 0xFF0000FF)
'        old = new
'    End If
 
        If new.Length <> old.Length Then
            LogString = new.SubString(old.Length)
            LogString = LogString.Replace(" HTTP/1.1", "")
            Dim cp() As String = Regex.Split(CRLF, LogString)
            For Each s As String In cp
'            If s.Contains(".html") Then
                Dim s2 As String = s.SubString2(0, s.LastIndexOf("SOURCE:"))
                If s2.Contains(".html") Or s2.ToLowerCase.Contains("mainpage") Then
                    If s2.Contains("[200]") Then
                        LogColor(s, xui.Color_Magenta)
                    Else If s2.Contains("[304]") Then
                        LogColor(s, 0xFFFF7F00)
                    Else If s2.Contains("[404]") Then
                        LogColor(s, xui.Color_Red)
                    End If
                Else
                    If s2.Contains("[200]") Then
                        LogColor(s, xui.Color_Blue)
                    Else If s2.Contains("[304]") Then
                        LogColor(s, 0xFFFF7F00)
                    Else If s2.Contains("[404]") Then
                        LogColor(s, xui.Color_Red)
                    End If
                End If
            Next

            old = new
        End If
    Catch
        Log(LastException.Message)
    End Try
End Sub
Here my log:
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
Initializing WebGL Library ...
Starting 3D engine ...
WebGL library initialized
Found 1929 file/s in 117 folder/s - Total of 2046 folders and files.
Threejs distribution folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL
Threejs [build] folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL\build
Threejs [library] folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL\examples\jsm
Threejs [project] folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL\examples
Start http server on port 8888
2024-08-05 09:41:43.395:INFO :eek:ejs.Server:JavaFX Application Thread: jetty-11.0.9; built: 2022-03-30T17:44:47.085Z; git: 243a48a658a183130a8c8de353178d154ca04f04; jvm 11.0.1+13
2024-08-05 09:41:43.579:INFO :eek:ejss.DefaultSessionIdManager:JavaFX Application Thread: Session workerName=node0
2024-08-05 09:41:43.606:INFO :eek:ejsh.ContextHandler:JavaFX Application Thread: Started o.e.j.s.ServletContextHandler@60f408b2{/,file:///C:/Users/Massimo/AppData/Roaming/B4XWebGL/,AVAILABLE}
2024-08-05 09:41:43.616:INFO :eek:ejs.RequestLogWriter:JavaFX Application Thread: Opened C:\Users\Massimo\AppData\Roaming\B4XWebGL\logs\b4j-2024_08_05.request.log
2024-08-05 09:41:44.899:INFO :eek:ejs.AbstractConnector:JavaFX Application Thread: Started ServerConnector@366a57a{HTTP/1.1, (http/1.1)}{0.0.0.0:8888}
2024-08-05 09:41:44.932:INFO :eek:ejs.Server:JavaFX Application Thread: Started Server@77f882fe{STARTING}[11.0.9,sto=0] @8889ms
Server started
WebGL ReadyToCode. Your WebGL code start here. URL: http://192.168.178.51:8888/examples/CubeTexture.html
crate.gif texture already exist: C:\Users\Massimo\AppData\Roaming\B4XWebGL\examples\textures\crate.gif
Already exist: C:\Users\Massimo\AppData\Roaming\B4XWebGL\examples\jsm\physics\Cloth.js
Save HTML file: C:\Users\Massimo\AppData\Roaming\B4XWebGL\examples\CubeTexture.html
Server static folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL
or
Server Log file name: b4j-2024_08_05.request.log
Server Log file path: C:\Users\Massimo\AppData\Roaming\B4XWebGL\logs\b4j-2024_08_05.request.log
Server Log File actually do not contain logs
192.168.178.51 - [05/08/2024 09:41:59 +0200] [200] GET /examples/CubeTexture.html (19627 Bytes) SOURCE: - :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:32 +0200] [200] GET /examples/CubeTexture.html (19627 Bytes) SOURCE: - :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:32 +0200] [200] GET /examples/jsm/loaders/DRACOLoader.js (13628 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:32 +0200] [200] GET /examples/jsm/controls/OrbitControls.js (32250 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:32 +0200] [200] GET /examples/jsm/libs/stats.module.js (3514 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:32 +0200] [200] GET /examples/jsm/libs/lil-gui.module.min.js (29526 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:32 +0200] [200] GET /examples/jsm/loaders/GLTFLoader.js (109781 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:32 +0200] [200] GET /build/three.module.min.js (674422 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:33 +0200] [200] GET /examples/jsm/physics/Cloth.js (14943 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:33 +0200] [200] GET /examples/jsm/utils/BufferGeometryUtils.js (31554 Bytes) SOURCE: http://192.168.178.51:8888/examples/jsm/loaders/GLTFLoader.js :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:33 +0200] [200] GET /examples/jsm/loaders/FBXLoader.js (101472 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:33 +0200] [200] GET /examples/jsm/curves/NURBSCurve.js (1878 Bytes) SOURCE: http://192.168.178.51:8888/examples/jsm/loaders/FBXLoader.js :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:33 +0200] [200] GET /examples/jsm/libs/fflate.module.js (89384 Bytes) SOURCE: http://192.168.178.51:8888/examples/jsm/loaders/FBXLoader.js :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:33 +0200] [200] GET /examples/jsm/curves/NURBSUtils.js (9150 Bytes) SOURCE: http://192.168.178.51:8888/examples/jsm/curves/NURBSCurve.js :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/models/fbx/Samba%20Dancing.fbx (3681360 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/cube/skybox/py.jpg (19634 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/cube/skybox/px.jpg (60050 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/cube/skybox/nx.jpg (55756 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/cube/skybox/ny.jpg (52198 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/cube/skybox/nz.jpg (54574 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/patterns/circuit_pattern2.png (6136 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/cube/skybox/pz.jpg (58868 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/terrain/grasslight-big.jpg (2595150 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/textures/terrain/grasslight-big-nm.jpg (2833920 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/models/gltf/Eve/eve$@walk.glb (15170672 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:38 +0200] [200] GET /favicon.ico (16958 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [05/08/2024 09:42:36 +0200] [200] GET /examples/models/gltf/Plant/Plant3.gltf (12108174 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
(Question 2)
Here I use LogColor to show my log requests, but what happen if the log is visualized on the command prompt instead of the B4X IDE ?
It is just used as normal Log by printing all the same color ? Or may not printed at all ?

(Question 3)
I think I've found a Jetty Server bug but I'm not sure. As you can see from the code, I set GMT+2.00 in the server log preferences, to set a right time offset
(seem it default use GMT+0.00) but for some strange reasons if I start the server eg. at 1.00 of night of eg. date 10 August (here in Italy), the server
do not create a new file, it just reuse the log file for a day before, so for a day 9 August even if current date is 10 August.
Even if the server is already started, it do not create new log file at 12:00 PM when the day change.

This is a reason that in my code I check the current day log, if not exist I try to get the day after, if not exist I check the day before.
For my use the day before something is necessary, but because this is a library I have to release on the forum, I searched to adapt it for any location checking even the day after. Any way to fix it ?

Many thanks for any help.
 
Last edited:
Solution
Here I use LogColor to show my log requests, but what happen if the log is visualized on the command prompt instead of the B4X IDE ?
It is just used as normal Log by printing all the same color ? Or may not printed at all ?
It will be printed non-color and with some "random" prefix.

Adding another log handler that prints to the logs:

1. Add this code to the main module:
B4X:
Private Sub AddLogHandler
    Dim server As JavaObject = srvr.As(JavaObject).GetField("server")
    Dim handler As JavaObject = server.RunMethod("getHandler", Null)
    If GetType(handler) = "org.eclipse.jetty.server.handler.gzip.GzipHandler" Then
        handler = handler.RunMethod("getHandler", Null)
    End If
    Dim handlers() As Object =...

Erel

B4X founder
Staff member
Licensed User
Longtime User
Here I use LogColor to show my log requests, but what happen if the log is visualized on the command prompt instead of the B4X IDE ?
It is just used as normal Log by printing all the same color ? Or may not printed at all ?
It will be printed non-color and with some "random" prefix.

Adding another log handler that prints to the logs:

1. Add this code to the main module:
B4X:
Private Sub AddLogHandler
    Dim server As JavaObject = srvr.As(JavaObject).GetField("server")
    Dim handler As JavaObject = server.RunMethod("getHandler", Null)
    If GetType(handler) = "org.eclipse.jetty.server.handler.gzip.GzipHandler" Then
        handler = handler.RunMethod("getHandler", Null)
    End If
    Dim handlers() As Object = handler.RunMethod("getHandlers", Null)
    Dim raw As String =  Me.As(JavaObject) 'ignore
    Dim PackageName As String = raw.SubString(raw.LastIndexOf(" ") + 1)
    Dim MyLogWriter As JavaObject
    MyLogWriter.InitializeNewInstance(PackageName & "$SimpleLogWriter", Null)
    Dim CustomRequestLog As JavaObject
    CustomRequestLog.InitializeNewInstance("org.eclipse.jetty.server.CustomRequestLog", Array(MyLogWriter, $"%{client}a - %u %t "%r" %s %O "%{Referer}i" "%{User-Agent}i""$))
   
    Dim LogHandler As JavaObject
    LogHandler.InitializeNewInstance("org.eclipse.jetty.server.handler.RequestLogHandler", Null)
    LogHandler.RunMethod("setRequestLog", Array(CustomRequestLog))
    Dim NewHandlersObjects(handlers.Length + 1) As Object
    Bit.ArrayCopy(handlers, 0, NewHandlersObjects, 0, handlers.Length)
    NewHandlersObjects(handlers.Length) = LogHandler
    Dim NewHandlers As JavaObject
    NewHandlers.InitializeArray("org.eclipse.jetty.server.Handler", NewHandlersObjects)
    handler.RunMethod("setHandlers", Array(NewHandlers))
End Sub


#if Java
public static class SimpleLogWriter implements org.eclipse.jetty.server.RequestLog.Writer {
     public void write(String requestEntry) throws java.io.IOException {
         System.out.println(requestEntry);
     }
}
#End If

2.
B4X:
srvr.As(JavaObject).SetField("MutableHandleCollection", True) 'requires jServer v4.02+
srvr.Start
AddLogHandler


********************************
jServer 4.02 allows setting the logs timezone:
B4X:
srvr.LogsTimezone = "GMT+3"
I haven't fully tested it so report your findings.

jServer v4.02 is attached.
 

Attachments

  • jServer.zip
    49.6 KB · Views: 56
Upvote 0
Solution

max123

Well-Known Member
Licensed User
Longtime User
Thank you Erel,

I will try your advices.?
And many thanks for jServer v4.02 that in B4J 10.00 is v4.01.?

I will report here my results.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I replaced all as your advices,
the project run, the server start but in the AddLogHandler I've an error on this line:
B4X:
MyLogWriter.InitializeNewInstance(PackageName & "$SimpleLogWriter", Null)
probably depends on PackageName ? It refer to b4xcollections that is null.

Here my log:
Waiting for debugger to connect...
Program started.
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
Initializing WebGL Library ...
Starting 3D engine ...
WebGL library initialized
Found 1928 file/s in 117 folder/s - Total of 2045 folders and files.
Threejs distribution folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL
Threejs [build] folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL\build
Threejs [library] folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL\examples\jsm
Threejs [project] folder: C:\Users\Massimo\AppData\Roaming\B4XWebGL\examples
Start http server on port 8888
2024-08-06 10:52:25.697:INFO :eek:ejs.Server:JavaFX Application Thread: jetty-11.0.9; built: 2022-03-30T17:44:47.085Z; git: 243a48a658a183130a8c8de353178d154ca04f04; jvm 11.0.1+13
2024-08-06 10:52:25.827:INFO :eek:ejss.DefaultSessionIdManager:JavaFX Application Thread: Session workerName=node0
2024-08-06 10:52:25.843:INFO :eek:ejsh.ContextHandler:JavaFX Application Thread: Started o.e.j.s.ServletContextHandler@c5c6310{/,file:///C:/Users/Massimo/AppData/Roaming/B4XWebGL/,AVAILABLE}
2024-08-06 10:52:25.848:INFO :eek:ejs.RequestLogWriter:JavaFX Application Thread: Opened C:\Users\Massimo\AppData\Roaming\B4XWebGL\logs\b4j-2024_08_06.request.log
2024-08-06 10:52:26.766:INFO :eek:ejs.AbstractConnector:JavaFX Application Thread: Started ServerConnector@393efc51{HTTP/1.1, (http/1.1)}{0.0.0.0:8888}
2024-08-06 10:52:26.785:INFO :eek:ejs.Server:JavaFX Application Thread: Started Server@642000a{STARTING}[11.0.9,sto=0] @13081ms
Emulated network latency: 100ms
Error occurred on line: 318 (WebGL)
java.lang.ClassNotFoundException: java$lang$b4xcollections=null
]$SimpleLogWriter
at anywheresoftware.b4j.object.JavaObject.getCorrectClassName(JavaObject.java:289)
at anywheresoftware.b4j.object.JavaObject.InitializeNewInstance(JavaObject.java:84)
at b4j.example.webgl._addloghandler(webgl.java:704)
at b4j.example.webgl$ResumableSub_GetEngine2.resume(webgl.java:317)
at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resumeAsUserSub(DebugResumableSub.java:47)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:234)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resume(DebugResumableSub.java:42)
at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:156)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:105)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at anywheresoftware.b4a.keywords.Common$3.run(Common.java:1118)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:834)
Here my last code, I changed the Server JavaObject name to joServer and the srvr with Server that refer to a server in the project.
I added as your advices the log Timezone, but I've a question here, I have to set both, even inside the Server.LogFormat ?
B4X:
Server.LogFormat = $"%{client}a %u %{dd/MM/yyyy HH:mm:ss ZZZ|GMT+2:00}t  [%s]  %r  (%O Bytes)    SOURCE: %{Referer}i :: %{User-Agent}i"$
Server.LogsTimezone = "GMT+2"
The LogsTimezone documentation says:
Screenshot 2024-08-06 112550.png

The code:
B4X:
Log("Start http server on port " & Port)

Server.Initialize("Server")
Server.Port = Port
Server.StaticFilesFolder = mRootDir
Server.LogsFileFolder = File.Combine(File.DirData("B4XWebGL"), "logs")
Server.LogsRetainDays = 1
Server.LogFormat = $"%{client}a %u %{dd/MM/yyyy HH:mm:ss ZZZ|GMT+2:00}t  [%s]  %r  (%O Bytes)    SOURCE: %{Referer}i :: %{User-Agent}i"$
Server.LogsTimezone = "GMT+2"

Server.AddHandler("/MainPage", "MyPageHandler", False) ' Handle main page

Server.As(JavaObject).SetField("MutableHandleCollection", True) 'requires jServer v4.02+
Server.Start
AddLogHandler

'TimerRequestsLog.Initialize("TimerRequestsLog", 500)
'TimerRequestsLog.Enabled = True
Log($"Server started"$)

Private Sub AddLogHandler
    Dim joServer As JavaObject = Server.As(JavaObject).GetField("server")
    Dim handler As JavaObject = joServer.RunMethod("getHandler", Null)
    If GetType(handler) = "org.eclipse.jetty.server.handler.gzip.GzipHandler" Then
        handler = handler.RunMethod("getHandler", Null)
    End If
    Dim handlers() As Object = handler.RunMethod("getHandlers", Null)
 
    Dim raw As String =  Me.As(JavaObject) 'ignore
    Dim PackageName As String = raw.SubString(raw.LastIndexOf(" ") + 1)
 
    Dim MyLogWriter As JavaObject
    MyLogWriter.InitializeNewInstance(PackageName & "$SimpleLogWriter", Null)  '<<< ERROR happen on this line
    Dim CustomRequestLog As JavaObject
    CustomRequestLog.InitializeNewInstance("org.eclipse.jetty.server.CustomRequestLog", Array(MyLogWriter, $"%{client}a - %u %t "%r" %s %O "%{Referer}i" "%{User-Agent}i""$))
 
    Dim LogHandler As JavaObject
    LogHandler.InitializeNewInstance("org.eclipse.jetty.server.handler.RequestLogHandler", Null)
    LogHandler.RunMethod("setRequestLog", Array(CustomRequestLog))
    Dim NewHandlersObjects(handlers.Length + 1) As Object
    Bit.ArrayCopy(handlers, 0, NewHandlersObjects, 0, handlers.Length)
    NewHandlersObjects(handlers.Length) = LogHandler
    Dim NewHandlers As JavaObject
    NewHandlers.InitializeArray("org.eclipse.jetty.server.Handler", NewHandlersObjects)
    handler.RunMethod("setHandlers", Array(NewHandlers))
End Sub

#if Java
public static class SimpleLogWriter implements org.eclipse.jetty.server.RequestLog.Writer {
     public void write(String requestEntry) throws java.io.IOException {
         System.out.println(requestEntry);
     }
}
#End If
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
The problem is that this is a class, a library, and the PackageName may refer to the main app package name ?
This will always change on every project where the library is imported, so I cannot set it static.

How I can get class package name if this do not seem to work ?
B4X:
Dim raw As String =  Me.As(JavaObject) 'ignore
Dim PackageName As String = raw.SubString(raw.LastIndexOf(" ") + 1)
As I know this refer the SimpleLogWriter Java class, and I'm pretty sure it can be referred, I used something like this in past to manage a WebView in a class and add WebChromeClient, so used some B4X code that refer to a WebChromeClient inside a Java class. Probably used something like Application.PackageName & "$MyJavaClass", but on B4A.

EDIT:
The code used in old project is:
B4X:
Dim jo as JavaObject
jo.InitializeNewInstance(Application.PackageName & ".myB4xClass$myJavaClass", Null) ' For a class
'or
jo.InitializeNewInstance(Application.PackageName & ".b4xmainpage$myJavaClass", Null) ' For a B4X Main Page

But B4J do not have Application.PackageName.

It refer to b4xcollections that is null.
Sorry, I'm wrong here, the error has nothing to do with B4XCollections, just these lines:
B4X:
Dim raw As String =  Me.As(JavaObject) 'ignore
Dim PackageName As String = raw.SubString(raw.LastIndexOf(" ") + 1)
extract a wrong string for package name that result in:
b4xcollections=null
because raw variable string end this way:
</script>
</body>
</html>
, minitialized=true, mupdated=false, mhtmlfilename=CubeTexture.html
, mpagetitle=CubeTexture, murl=http://192.168.178.51:8888/examples/CubeTexture.html, mservermainpath=http://192.168.178.51:8888/
, mservermainpagepath=http://192.168.178.51:8888/MainPage/, mserverprojectpath=http://192.168.178.51:8888/examples/, mserverlocalprojectpath=http://localhost:8888/examples/
, mlogsfilefolder=, mlogsfilename=, mlogolddate=
, old=, new=, logstring=
, timerrequestslog=anywheresoftware.b4a.objects.Timer@2116d755, mrootdir=C:\Users\Massimo\AppData\Roaming\B4XWebGL, mdebug=false
, main=null, b4xpages=null, b4xcollections=null
]
b4xcollections=null
]
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Ok, I found the way to go.... and I'm happy I learned something new again. This worked:
B4X:
    Dim PackageName As String = GetType(Me)
    Log("PackageName: " & PackageName) ' b4j.example.webgl
    Dim MyLogWriter As JavaObject
    MyLogWriter.InitializeNewInstance(PackageName & "$SimpleLogWriter", Null)

Now the java class is called and logs printed to B4X IDE log.

Now there are 2 problems.
1) Changing the timezone have no effect:
B4X:
Server.LogsTimezone = "GMT+2"
Tried to put it before and after Server.Start, nothing change.
The log file is same as before, just as specified on this line, and this is good:
B4X:
Server.LogFormat = $"%{client}a %u %{dd/MM/yyyy HH:mm:ss ZZZ|GMT+2:00}t  [%s]  %r  (%O Bytes)    SOURCE: %{Referer}i :: %{User-Agent}i"$
but on the B4X IDE the timezone always is GMT +0000

2) The logs on the B4X IDE do not follow the right pattern, just is a default from jServer library without changing the format.

Here some log requests printed by Java to B4X IDE log:
192.168.178.51 - - [06/ago/2024:14:23:07 +0000] "GET /examples/screenshots/webgl_geometry_csg.jpg HTTP/1.1" 200 6506 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:07 +0000] "GET /examples/screenshots/webgl_geometry_cube.jpg HTTP/1.1" 200 12859 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:08 +0000] "GET /examples/screenshots/webgl_geometry_dynamic.jpg HTTP/1.1" 200 10508 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:08 +0000] "GET /examples/screenshots/webgl_geometry_extrude_shapes.jpg HTTP/1.1" 200 23072 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:08 +0000] "GET /examples/screenshots/webgl_geometry_extrude_splines.jpg HTTP/1.1" 200 16929 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:08 +0000] "GET /examples/screenshots/webgl_geometry_minecraft.jpg HTTP/1.1" 200 50036 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:08 +0000] "GET /examples/screenshots/webgl_geometry_nurbs.jpg HTTP/1.1" 200 32664 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:09 +0000] "GET /examples/screenshots/webgl_geometry_sdf.jpg HTTP/1.1" 200 12088 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
192.168.178.51 - - [06/ago/2024:14:23:09 +0000] "GET /examples/screenshots/webgl_geometry_shapes.jpg HTTP/1.1" 200 63011 "http://192.168.178.51:8888/examples/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
But I expected to be in the format I specified with Server.LogFormat command, so the same on the log file, eg:
192.168.178.51 - [06/08/2024 14:11:13 +0200] [200] GET /examples/CubeTexture.html HTTP/1.1 (19627 Bytes) SOURCE: - :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:11:13 +0200] [304] GET /examples/jsm/physics/Cloth.js HTTP/1.1 (0 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:11:17 +0200] [304] GET /examples/models/gltf/Plant/Plant3.gltf HTTP/1.1 (0 Bytes) SOURCE: http://192.168.178.51:8888/examples/CubeTexture.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:18:25 +0200] [304] GET /examples/CubeTexture.html HTTP/1.1 (0 Bytes) SOURCE: - :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/ HTTP/1.1 (9405 Bytes) SOURCE: - :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/files/thumbnails.svg HTTP/1.1 (358 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /files/main.css HTTP/1.1 (11422 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /files/ic_code_black_24dp.svg HTTP/1.1 (261 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /files/ic_search_black_24dp.svg HTTP/1.1 (403 Bytes) SOURCE: http://192.168.178.51:8888/files/main.css :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/files.json HTTP/1.1 (13035 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /files/RobotoMono-Medium.woff2 HTTP/1.1 (10780 Bytes) SOURCE: http://192.168.178.51:8888/files/main.css :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /files/RobotoMono-Regular.woff2 HTTP/1.1 (10660 Bytes) SOURCE: http://192.168.178.51:8888/files/main.css :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/tags.json HTTP/1.1 (5917 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_animation_keyframes.jpg HTTP/1.1 (40887 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_animation_skinning_ik.jpg HTTP/1.1 (37541 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_animation_skinning_morph.jpg HTTP/1.1 (12682 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_animation_skinning_blending.jpg HTTP/1.1 (14241 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_animation_multiple.jpg HTTP/1.1 (14796 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_camera_array.jpg HTTP/1.1 (39522 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_animation_skinning_additive_blending.jpg HTTP/1.1 (12132 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_camera.jpg HTTP/1.1 (38983 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /examples/screenshots/webgl_camera_cinematic.jpg HTTP/1.1 (47425 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:45 +0200] [200] GET /files/favicon_white.ico HTTP/1.1 (16958 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:25:47 +0200] [200] GET /examples/screenshots/webgl_camera_logarithmicdepthbuffer.jpg HTTP/1.1 (39655 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:27:25 +0200] [200] GET /examples/webgl_animation_keyframes.html HTTP/1.1 (3401 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:27:26 +0200] [200] GET /examples/main.css HTTP/1.1 (1403 Bytes) SOURCE: http://192.168.178.51:8888/examples/webgl_animation_keyframes.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:27:26 +0200] [200] GET /examples/jsm/environments/RoomEnvironment.js HTTP/1.1 (3735 Bytes) SOURCE: http://192.168.178.51:8888/examples/webgl_animation_keyframes.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:27:26 +0200] [200] GET /build/three.module.js HTTP/1.1 (1274691 Bytes) SOURCE: http://192.168.178.51:8888/examples/webgl_animation_keyframes.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:27:26 +0200] [404] GET /examples/models/gltf/LittlestTokyo.glb HTTP/1.1 (519 Bytes) SOURCE: http://192.168.178.51:8888/examples/webgl_animation_keyframes.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:31:22 +0200] [200] GET /examples/webgl_animation_skinning_blending.html HTTP/1.1 (12401 Bytes) SOURCE: http://192.168.178.51:8888/examples/ :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
192.168.178.51 - [06/08/2024 14:31:22 +0200] [404] GET /examples/models/gltf/Soldier.glb HTTP/1.1 (514 Bytes) SOURCE: http://192.168.178.51:8888/examples/webgl_animation_skinning_blending.html :: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0
Note that the time in these 2 examples seem the same, but really I generated at distance of 2 hours, the last on the file have right GMT and right time, the first one printed to the B4X IDE log do not.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Please help with this last step, or I'm not able to use it.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Thanks @Erel now it works as expected.
Sorry I don't know how I missed this line that set the log pattern, may confused me a short line.

It is a mistake to post several questions / issues in the same thread. Every thread should be as focused as possible.
I know you, but so to just solve one problem I have to post more threads ?
Note, this is not a provocation, this is just a question although maybe not much related here.

I started this thread to just do one thing, log server logs on B4X IDE, and continued the thread based on
results of code to just solve the same problem until it is working, and now it's working.

Many thanks for help and for this new feature.

As reference for users this is a full working code. Here I use raiseEvent2 to call B4X sub with the log request string, in my use case, I parse it and use LogColor to show different colors based on HTTP status responses. Hope this help some users that in future need it.
B4X:
Log("Start http server on port " & Port)

Server.Initialize("Server")
Server.Port = Port
Server.StaticFilesFolder = mRootDir
Server.LogsFileFolder = File.Combine(File.DirData("B4XWebGL"), "logs")
Server.LogsRetainDays = 1
Server.LogFormat = $"%{client}a %u %{dd/MM/yyyy HH:mm:ss ZZZ|GMT+2:00}t  [%s]  %r  (%O Bytes)    SOURCE: %{Referer}i :: %{User-Agent}i"$
Server.LogsTimezone = "GMT+2"  ' Check it

Server.AddHandler("/MainPage", "MyPageHandler", False) ' Handle main page
Server.As(JavaObject).SetField("MutableHandleCollection", True) ' Requires jServer v4.02+
Server.Start
AddLogHandler                 
Log($"Server started"$)

'.....

Private Sub AddLogHandler
    Dim joServer As JavaObject = Server.As(JavaObject).GetField("server")
    Dim handler As JavaObject = joServer.RunMethod("getHandler", Null)
    If GetType(handler) = "org.eclipse.jetty.server.handler.gzip.GzipHandler" Then
        handler = handler.RunMethod("getHandler", Null)
    End If
    Dim handlers() As Object = handler.RunMethod("getHandlers", Null)
 
    Dim PackageName As String = GetType(Me)
    Log("PackageName: " & PackageName) ' b4j.example.webgl
    Dim MyLogWriter As JavaObject
    MyLogWriter.InitializeNewInstance(PackageName & "$SimpleLogWriter", Null)
 
    Dim CustomRequestLog As JavaObject
'    CustomRequestLog.InitializeNewInstance("org.eclipse.jetty.server.CustomRequestLog", Array(MyLogWriter, $"%{client}a - %u %t "%r" %s %O "%{Referer}i" "%{User-Agent}i""$))
    CustomRequestLog.InitializeNewInstance("org.eclipse.jetty.server.CustomRequestLog", Array(MyLogWriter, $"%{client}a %u %{dd/MM/yyyy HH:mm:ss ZZZ|GMT+2:00}t  [%s]  %r  (%O Bytes)   SOURCE: %{Referer}i :: %{User-Agent}i"$))
 
    Dim LogHandler As JavaObject
    LogHandler.InitializeNewInstance("org.eclipse.jetty.server.handler.RequestLogHandler", Null)
    LogHandler.RunMethod("setRequestLog", Array(CustomRequestLog))
    Dim NewHandlersObjects(handlers.Length + 1) As Object
    Bit.ArrayCopy(handlers, 0, NewHandlersObjects, 0, handlers.Length)
    NewHandlersObjects(handlers.Length) = LogHandler
    Dim NewHandlers As JavaObject
    NewHandlers.InitializeArray("org.eclipse.jetty.server.Handler", NewHandlersObjects)
    handler.RunMethod("setHandlers", Array(NewHandlers))
End Sub

Private Sub Print_ServerLog (Text As String)
    If mLogRequests = False Then Return
 
    Dim s As String = Text.SubString2(0, Text.LastIndexOf("SOURCE:"))
    If s.Contains(".html") Or s.ToLowerCase.Contains("mainpage") Then
        If s.Contains("[200]") Then
            LogColor(Text, xui.Color_Magenta)
        Else If s.Contains("[304]") Then
            LogColor(Text, 0xFFFF7F00)
        Else If s.Contains("[404]") Then
            LogColor(Text, xui.Color_Red)
        End If
    Else
        If s.Contains("[200]") Then
            LogColor(Text, xui.Color_Blue)
        Else If s.Contains("[304]") Then
            LogColor(Text, 0xFFFF7F00)
        Else If s.Contains("[404]") Then
            LogColor(Text, xui.Color_Red)
        End If
    End If
End Sub

#If JAVA
import anywheresoftware.b4a.BA.RaisesSynchronousEvents;
static BA ba;

public static class SimpleLogWriter implements org.eclipse.jetty.server.RequestLog.Writer {
     public void write(String requestEntry) throws java.io.IOException {
       //  System.out.println(requestEntry);
      
         String sub = "Print_ServerLog";
         ba.raiseEvent2(this, false, sub.toLowerCase(), true, requestEntry); 
      }
}
#End If
 

Attachments

  • Immagine 2024-08-08 135801.png
    Immagine 2024-08-08 135801.png
    225.6 KB · Views: 67
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Just one important note here....

In my code I posted (that is a Class), when I compiled as library, the LogColor always show single color
in the main code that use the library.

If someone have this issue, just use callSubDelayed2 to pass the text log to the calling module,
here you can then use LogColor and it will work correctly.
 
Upvote 0
Top