Skip to main content
Skip table of contents


In this section we provide details on the ins and outs of the console and file logger. We will discuss some key concepts, instrumenting your code, setting log levels, and some advanced output options.

Key concepts

Standard logging provides visibility into the activities of the running system over time. The model should log sufficient information to facilitate debugging and problem identification. NexJ’s platform provides:

  • Flexible control over the level-of-detail that is logged
  • Code instrumentation with the logger function
  • Flexible output options and filtering

NexJ integrates with Log4j. Log4j has three main components: loggers, appenders and layouts. These allow you to log messages according to type and level, and to control at run time how these messages are formatted, and where they are reported. Configuration of the Log4j environment is typically done at application initialization from a configuration file or VM arguments, although there is an interesting article on the community about Setting the log level in a running console. There are other ways of looking into your running code, such as process logging, and statistics/monitoring, which are discussed elsewhere.

So, let’s talk about Loggers, Appenders, and Layouts…


Loggers are typically named after the component from which they are called (for example, nexj.core.meta.Metaclass.Person). They generate log entries, and they follow a hierarchical naming rule. For example, the logger named “nexj.core” is a parent of the logger named “nexj.core.meta”. Parents will output all logs generated by their children. In another example, “java” is a parent of “java.util” and is an ancestor of “java.util.Vector”. There is a special root logger that always exists.

For our purposes, loggers may be assigned the following levels: dump, debug, info, warn, error, and fatal. Levels are ordered where dump < debug < info < warn < error < fatal.

These logging requests are made in Scheme as:

(logger'debug "This is my log statement")

The logger function’s printing methods (dump, debug, info, warn, error, and fatal) determine the output level of a logging request. A logging request is enabled and will be printed if its level is higher than or equal to the current logging level of the running server. Otherwise, the request is disabled and will not be printed.


An output destination for log statements is called an appender. Appenders can be configured for the console, files, GUI components, remote socket servers, JMS, Mail Systems, Windows Event Loggers, and remote UNIX Syslog daemons.  It is also possible to log asynchronously. Loggers may output to multiple appenders. Each appender may have it’s own layout. By default, the Server Console outputs to the console.


PatternLayouts let you specify output formats. For example, a PatternLayout with the conversion pattern of "%r [%t] %-5p %c - %m%n" will output something like: 176 [main] INFO - The value of x is 10.


  • The first field is the number of milliseconds elapsed since the start of the program.
  • The second field is the thread making the log request.
  • The third field is the level of the log statement.
  • The fourth field is the name of the logger associated with the log request.
  • The text after the ‘-‘ is the message of the statement.

Pattern options can be found at org.apache.logging.log4j.core.layout

The layout for the NexJ Studio console may be set with the following VM arguments in the Scheme Console settings (in the Run Scheme Console/Scheme Console Settings toolbar item or the Window/Preferences… NexJ Studio/Launch Settings/Scheme Console menu item).


where the pattern is something like "; %d{HH:mm:ss,SSS} %p [%c{1}] (%t) %m%n".

Instrumenting your code with the logger function

NexJ’s Model Server is already instrumented with logging statements. These statements will be output if they are enabled which depends on the server’s current logging level.

You may instrument your script using (logger arg1 arg2…argN) where arg1 is one of ‘fatal, ‘error, ‘warn, ‘info, ‘debug or ‘dump. It prints its arguments separated by spaces. The arguments are evaluated only if the corresponding log level is enabled. Additionally, there is a log step that makes it easy to log from within services and workflows.

For example:

(logger'debug "x =" (+ 1 2)) => "x = 3"

Code should use the logger methods corresponding to individual logging levels as follows:

  • Fatal – the application cannot execute any request (for example, when a data source cannot be found, the message queue is unavailable, or there is a memory overflow). A sysadmin is usually paged to address the problem immediately.
  • Error – the application cannot continue executing a small class of requests (for example, because incorrect data has been passed from another layer, or there are service configuration problems). User errors and optimistic locking errors are reported at the Debug level instead.
  • Warning – potential application problem (for example, a query executes longer than a predefined threshold, there is a hacker alert, or the maximum resource pool size is reached). The production systems are configured to output this level and the higher-priority levels.
  • Info – information about application progress (for example, configuration values, or service startup/shutdown). The amount of the logged information is not proportional to the number of handled requests. If it is proportional, use the Debug level instead.
  • Debug – detailed debugging information that can be used for identifying problems without a debugger (for example, entry/exit points, user errors, recoverable errors, or algorithm steps). The logged messages usually do not exceed 255 characters. The application performance is significantly reduced when this logging level is enabled. Not for production use.
  • Dump – dump of object state for very detailed debugging. The log files will grow rapidly.

These statements may be placed anywhere in your code.

Setting log levels

To see logging in action, start the server console in NexJ Studio. You should see log statements as the model server starts up and loads the model.  

By default, the output looks something like:

; 09:58:44,717 DEBUG [ObjectConsumerPool] (NexJ-Worker-3) Renewing listener thread: message-puller
; 09:58:44,717 DEBUG [ObjectConsumerPool] (NexJ-Worker-13) Consumer pool received getMessage request
; 09:58:44,717 DEBUG [ObjectConsumerPool] (NexJ-Worker-7) Receiving client connection
; 09:58:44,717 DEBUG [ObjectConsumer] (NexJ-Worker-6) Deactivated ObjectConsumer@1503572282(DefaultObjectConsumerPool@1047246184(tx=false, config=ObjectConsumerConfig@1804976190(port="1111")))
; 09:58:44,717 DEBUG [ObjectConsumer] (NexJ-Worker-7) Activating ObjectConsumer@1503572282(DefaultObjectConsumerPool@1047246184(tx=false, config=ObjectConsumerConfig@1804976190(port="1111")))
; 09:58:44,717 DEBUG [ObjectConsumerPool] (NexJ-Worker-7) Renewing listener thread: socket-acceptor
; 09:58:44,717 DEBUG [ObjectConsumer] (NexJ-Worker-6) Handling request to dispatcher (3, [localhost, 60000])
; 09:58:44,718 DEBUG [ObjectQueueDispatcher] (NexJ-Worker-6) Received getMessage request from node localhost
The default pattern layout shown above is generated with a conversion pattern of "; %d{HH:mm:ss,SSS} %p [%c{1}] (%t) %m%n".

Stop the console. From the Run Scheme Console toolbar drop-down menu, select Scheme Console Settings. You will see the Scheme Console Settings dialog with the Default Log Level and Common VM Arguments. Notice you can set the level and arguments specifically for any of the console types or globally. Supported levels for the server are ERROR, WARN, INFO, DEBUG, and ALL, where ERROR is the least verbose and ALL is the most. Different servers may have different names for these levels (for example, ALL may be DUMP).

Change the log level to ALL in the preferences/Scheme Console Settings, and restart the server. You will see much more output.

For information on configuring logging in different containers, see:

Advanced output

Output from the standard Model Server logging can sometimes get in the way when in Debug. Console information quickly disappears into the past because queues and timers are firing and logging activity from integration and the database. Sometimes more advanced control over the behavior of the logger is desirable.

Filtering with categories

Log statements are categorized by source. All Model Server categories begin with “nexj.core”.  Some useful categories include:

  • integration
  • meta
  • monitoring
  • persistence
  • rpc
  • runtime
  • scripting

Categories allow you to set different log options for different loggers. For example, if you only want to log output from the persistence layer at DEBUG level, set the console to INFO level, and add the following statements to the VM section of the Scheme Console settings:


This will enable all log statements at INFO or above but will enable nexj.core.persistence.* log statements at DEBUG  or above.

To more specifically log only database persistence, change the statement to:


Logging specific metadata

It’s possible to specify logging down to the metadata level.  For example ,classes may be specified in categories by appending the metadata class name to the nexj.core.meta.Metaclass. In this case, to change the log level of Person to WARN, enter the following as VM arguments:


The same concept may be applied to integration services and business model workflows. To log activities in a service called MyService at DEBUG level, enter the following as a VM argument:


To log activities in a workflow called MyWorkflow at DEBUG level, enter the following as VM arguments to the server console settings:


To log activities in all workflows, enter:


As you can see, the logger offers very fine control over the breadth and scope of the level of information to output to the logs.

Logging Server Console output to a file

To write the console output to a file, add the following VM arguments:

Make sure to set the log4j.appender.rolling.fileName path appropriately for your computer.


//Add appender to the root logger
//Define type (also set name)
//Set max file size of log.  If adding one or more policies, first line must be added
//Set max number of rollover files
//Set file location
//Set pattern
-Dlog4j.appender.rolling.layout.pattern=%d{ABSOLUTE} %-5p: %m%n

The appender name “fileName” in the above example could be any other name, and the example would work the same.

Logging messages from specific loggers in separate log file 

Log statements for specific loggers can be logged into a separate file by creating an appender, and associating a specific logger with it.

The code below illustrates how the appender created in the previous section could be used to log statements from the MyService service to that file.

//Add appender to the MyService logger
-Dlog4j.logger.nexj-model-service-MyService.appenderRef.rolling.ref = RollingFile

Run the server console and look in the out.txt file.

Routing the standard error and output feeds to a log4j appender

To redirect the standard error and standard output feeds to one or more log4j appenders, set the following VM arguments:


Notes regarding these options

The .level argument specifies the level to use when writing the information from the error or output feed. It is not used to filter or limit what is written.

You can specify multiple appenders using a comma-separated list as the argument value. For example, specifying -Dlog4j.stderr.appenders=SYSTEMERR, MYAPNDR will send the output to both the SYSTEMERR and MYAPNDR appenders.

The .additivity argument is optional, but will default to true if unspecified, which may cause unwanted additional logging of the error and output feeds.

Other useful categories


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.