Server Logs
The server console displays a lot of useful information, from server start, configuration application, launching various processes, information about connections and requests and responses (responses are output in a short form, as it can be a large volume of data).
Also, of course, everything that the developer decided to output in their methods and modules (via console) is output. However, as a rule, there are few such logs, and they should be removed after debugging so as not to clutter the log.
In methods, it sometimes makes sense to leave logs of the console.error type in places where behavior does not match the thought-out logic. At the same time, we are talking not about checking parameters, but more about emergency situations. This will give the opportunity to have information about what went wrong in case of failures. Parameter checking, as well as other checks, should be handled by the standard mechanism of exiting the function with a corresponding response (IError interface).
Some aspects of the output can be managed, which will be described below.
In various modules, there may be their own additional settings that can include more detailed logging. It was needed during the development of these modules and is not needed now, but if something works wrong, you can look at the code and find some flag at the beginning of the file that will help better understand what is happening. Most likely, you will not need this.
The information in the logs is ordered and has a certain structure, which we will now describe:
Logging starts with the server start and an indication of which configuration file is selected:
Configuration file selected: config.json
To select a different config, you need to specify it as the second (after the js file name) parameter at startup: “node bin/www.js testConfig.json”
Next, the MySQL settings taken from the configuration are set. Messages of the type “INFO: cMysql.INIT. …”. They are output via error, as is the subsequent message about the server startup:
ERROR: 10.07.2025 12:15:07 SERVER STARTED Server time: Thu Jul 10 2025 12:15:07 GMT+0300 (Moscow Standard Time)
Outputting these messages via the error stream is intentional, as it allows easily finding the start/restart point among all logs (of this process) on the server. Moreover, from a production point of view, a server restart is indeed a significant event, so it should be in a separate stream that is looked at first.
Next, there should be no messages in the error stream, and if there are, they should be paid attention to.
Then follows information about the address where the server is running
Server running at http://127.0.0.1:7011/
Next are several messages from the background task service. First of all, there is a message about how long the startup process will take, as they are launched delayed so as not to give extra load at the very beginning when everyone is reconnecting.
BJ ==> INFO Background tasks will start running in 300
…
BJ ==> INFO The following tasks are excluded from startup by the configuration file []
BJ ==> INFO These tasks will be started […]
When a client connects (via socket), there will be a message of the following type: io.on.connection:count: 2. When it disconnects: socket on disconnect 4BOQu1pNzJJvs9lnAAAL transport close.
Request Exchange with Client and Between Methods
All requests pass through the internal API and enter logging.
Request Information
Requests from a client (whether it is a web interface, an API call, or a mobile application) open a chain of requests, and all internal calls to other methods (if the initial method calls something else) continue this chain, that is, they become children of the methods that called them. Thus, in the logs we see the entire chain, who called whom.
Consider examples of a request.
11.07.2025 10:36:53.611 f437c7d7-db07-4ca4-876e-b0749c6e5e73: → 48DE98AA_User.get_me (fromClient) {“getRoles”:false}
11.07.2025 10:36:53.612 f437c7d7-db07-4ca4-876e-b0749c6e5e73: ← 48DE98AA_User.get_me (fromClient) ←1 UserError: noAuth -4 noAuth User.get_me { message_en: ‘Please log in.’ }
In the beginning, there is the date and time.
Although the server log itself logs the recording time, its own time in the logs is much more convenient when searching for problems.
Next comes the SID.
For an authorized user, you will be able to find their session in the system or in the database if it has already ended. You can also filter logs by it if you want to see only for them.
If the request is internal, then as many “_” (underscore) characters are indicated as the nesting level of the request has.
Next, the arrow indicates the direction. A forward arrow is a request, and a backward arrow is a response.
Then comes the request ID, also containing a unique number and a chain of calls in the format <ClassName>.<MethodName>. At the same time, if the next method in the chain belongs to the same class as the parent one, then the class name is omitted.
EA55DED2_User.get_me - Access_to_operation.loadAccess - user_role.get
or
3629393D_menu.get_menu_tree - .get (here the class name before “get” is omitted, as it also belongs to the “menu” class).
If the request came from outside (not internal), then “(fromClient):” follows. You can also filter by it so that internal requests do not interfere.
Next, for the request (when it arrives) comes the content of the parameters, and if it is already a response, then a left arrow, the method execution time, and the response message text (without the response body).
2025 12:45:42.477 f437c7d7-db07-4ca4-876e-b0749c6e5e73: fromClient: ← DD58E88A_User.login ←134 noToastr
Often you can see the response “noToastr”, it is returned by methods that do not provide for displaying a message to the user.
Here is what a set of requests looks like, starting with an external entry, continuing with internal requests, and ending with a response:
11.07.2025 10:41:00.256 f437c7d7-db07-4ca4-876e-b0749c6e5e73: → D296E26E_menu.get_menu_tree (fromClient) {}
11.07.2025 10:41:00.272 f437c7d7-db07-4ca4-876e-b0749c6e5e73: _ → D296E26E_menu.get_menu_tree - .get {“where”:[{“key”:“is_visible”,“val1”:true}],“sort”:“sort_no,name”,“limit”:1000000}
11.07.2025 10:41:00.347 f437c7d7-db07-4ca4-876e-b0749c6e5e73: _ ← D296E26E_menu.get_menu_tree - .get ←75 noToastr
11.07.2025 10:41:00.348 f437c7d7-db07-4ca4-876e-b0749c6e5e73: ← D296E26E_menu.get_menu_tree (fromClient) ←92 noToastr
The system hides some secure parameters when outputting to the console, outputting “***” instead, for example, the “password” parameter in the User.login method.
Such parameters are listed in excludedConsoleParams in api/apiConfig and accordingly in the default and project files. If you want to expand the list, add to it in the project.ts file. You can use not a full parameter name match but “starts with” and “ends with”, using the “*” character.
“log:api:” Configuration
You can configure what information to output. Settings are located in the configuration file config/config.json in the “log:api:” section.
fromClientOnly. Allows disabling the logging of internal requests. Do not disable on production, as this is quite valuable information.
logStart. Whether to output to the console when a request arrives.
logFinishUserOk. Whether to output to the console when a request is completed and sent to the client if the response is UserOk.
logFinishUserError. Whether to output to the console when a request is completed and sent to the client if the response is UserError.
logFinishMyError. Whether to output to the console when a request is completed and sent to the client if the response is MyError.
logFinishUnknown. Whether to output to the console when a request is completed and sent to the client if the response is not one of the above types. This should not happen, it is put just in case if developers add a new type corresponding to IAPIResponse.
logBadCommand. Whether to output to the console when a request accesses a non-existent method. You should not enable this parameter just like that. Such errors may well happen, for example, when someone is debugging work with your service via API and makes mistakes. Although it can be enabled on production, since there should be no debugging there and if such commands exist, they should be logged and investigated.
SQL Logging
The system allows logging what SQL queries are formed. This only applies to queries of the SELECT type.
For some reason, during all the time of work, there was no need to log other types of SQL queries (specifically SQL, as we see that the method, for example “modify”, was called and with what parameters), so this was not done.
In the course of its work, the core can make various additional (service) queries that are marked with the doNotLog parameter. Such queries are hidden from logging by default, both in api and SQL queries. This can be changed with the ignoreDoNotLog parameter.
A regular get request makes two queries, one to count the number by these conditions, and the second directly a data query. Both of these queries can be logged or not. More details below.
In fact, the core does a lot of different work, including pulling data from directories by system names, checking for uniqueness, and more. In addition, the caching system is arranged quite cleverly, so it is not always immediately clear why the system makes certain subqueries (something from the cache, something from the database). Such queries as a rule go with the doNotLog flag already mentioned, and they should not be paid attention to. It is described here so that when debugging any of your queries, having turned on all logging, you are aware that different processes can occur and this is normal - they ensure optimal interaction with the database, with a proper level of development convenience.
The core can log long queries; such queries are logged to the “error” stream (by default), which makes it easy to detect them and take measures. You can configure parameters for this mechanism, see “log:sql:” Configuration.
“log:sql:” Configuration
You can configure what information to output. Settings are located in the configuration file config/config.json in the “log:sql:” section.
countStart. Whether to output to the console an SQL query for COUNTING before its execution in the database.
countFinish. Whether to output to the console an SQL query for COUNTING after its execution in the database.
selectStart. Whether to output to the console an SQL query for DATA RETRIEVAL before its execution in the database.
selectFinish. Whether to output to the console an SQL query for DATA RETRIEVAL after its execution in the database.
selectFromCache. Whether to output to the console SQL queries for COUNTING and DATA RETRIEVAL when receiving them from the cache.
For such queries, there is only “before receiving”.
ignoreDoNotLog. Output the above-listed queries according to their settings, including for queries with the doNotLog parameter. Sometimes it helps to debug a complex case.
debugLongSql. Enables logging of long queries even if all other logging is disabled.
longSQLTime. Determines in milliseconds above what time a query should be executed to be considered “long” and enter the log.
longSQLConsoleFn. You can override which method to call on the console object when logging long queries. By default, console.error(...) is executed.
Saving to the Database
The system automatically saves some errors to the database, and they can be viewed through the system interface. Menu System -> Error Log.
By default, the system saves responses of methods of the MyError type, as well as all console.error output during server operation. Also, when an uncaught exception occurs somewhere on the server (uncaughtException), it is caught at the highest level and also logged.
Exceptions are errors related to database access.
Setting up the DB Logging System
You can configure exactly what will be logged to the database via the system interface. Moreover, these settings will be applied on the fly, that is, you will not need to restart the server for the changes to take effect.
Settings are made via the System -> System Settings table (you may encounter the outdated name “Client Settings”).
You need to change or create (it may not be created) a row with the system name “LOG_ERRORS”.
In “Value 1”, list comma-separated types of logged errors from this list: ANY|NO|MYERROR|USERERROR|UNKNOWN. If among the listed there is the value NO, then no errors will be logged. If there is ANY (but no NO), then any types of errors will be logged.
In “Value 2”, list comma-separated sources of logged errors from this list: ANY|NO|API|LOG|THROW. The values NO and ANY work the same as for types. API - if the error is in the response from a method called via internal API, LOG - error output via console.error, THROW are uncaught errors.
As indicated above, you can configure error types and error sources. By default, ANY and ANY are used.
Logging from Client via Socket
The system supports the ability to write to the server log messages sent from the client via socket to the “logFromClient” channel.
socket.on('logFromClient', (data) => { ... })
This mechanism is especially useful for debugging widgets or mobile applications when there is no possibility to view logs on the client side; important details can be logged in this way via the server.
Such a log is highlighted in a block:
logFromClient START 1 2025.07.11 13:40:18
{ msg: ‘TEST’, abc: 489 }
logFromClient END 1
After the word START goes the ID of the user for whom it is logged.
By default, the server ignores such sends, but you can enable logging in the settings and specify the users from whom to accept such messages.
“log:socket:” Configuration
logFromClient. Enables or disables logging.
logFromClientUsers. Array with user IDs for whom to log. You can specify “-” to log from unauthorized users.
Access Denied Log
As described in the section on access, denials are logged in Access -> Access Denials.
Authorization Denied Log
Similarly to access denials, failed authorization attempts are also logged. Access -> Authorization Denials.
Fields logged: user_id, login, sid, user_agent, address, err.
The entered password, naturally, is not logged.
Viewing Logs on the Server
As a rule, on the server, the process is deployed in a container, and you can view logs through a standard journal with filtering by container.
Example: journalctl --since "2025-07-03 07:00:00" --until "2025-07-03 11:00:00" CONTAINER_NAME=app | grep -C 2 "MyError".
If you deployed the server according to the instructions in this documentation, then you can type ./start.sh log ccs_app, where ccs_app is the service name.