Skip to content

Logging

You can enable server side logging in Kittox, which will allow you to see trace data useful for debugging or log your own data from your server side code (such as custom controllers or rules, for example). The logging system is pluggable and multiple loggers can be active at once.

Logging to file

In order to enable logging to file, you write something like this in your Config.yaml:

yaml
Log:
  # 1 = Minimal, 5 = Debug.
  Level: 5
  TextFile:
    FileName: %APP_PATH%log.txt
  # Set this to false to disable this logger without
  # deleting its configuration.
  IsEnabled: True

The code above uses the TextFile logger, which you also need to enable in your application by referencing the unit EF.Logger.TextFile (usually in your UseKitto.pas file). If you fail to include the relevant unit, your logging configuration will be ineffective.

Log levels

The Level parameter controls the verbosity of log output:

LevelDescription
1Minimal — errors and critical events only
2Warnings
3Informational messages
4Verbose
5Debug — full trace output

WARNING

Level: 5 generates huge amounts of data; use it only while debugging.

Available loggers

LoggerUnitConfig sectionDescription
TextFileEF.Logger.TextFileTextFileWrites to a plain text file
CodeSiteEF.Logger.CodeSiteCodeSiteSends log data to the CodeSite viewer (any edition)

Each logger section must contain at least IsEnabled: True. You can disable a logger without removing its configuration by setting IsEnabled: False. To log to file and CodeSite at the same time, just add both sections under the Log node.

Passwords in the log

Credentials never reach the log: before a message is written, the value assigned to anything whose name contains password is replaced with ***. All the shapes a message can carry one in are covered — Password=value from a query string, "Password":"value" from JSON, PASSWORD_HASH: value from a SQL trace.

The message itself is kept. A line that merely mentions the word — a marker, an error such as Old Password is wrong, the name of a method — is logged unchanged, so authentication stays diagnosable.

Why this matters when you are debugging

Earlier versions dropped the whole line whenever it contained the word. Anything you added to trace an authentication problem disappeared silently, which made the execution look as if it stopped between two consecutive statements. If you are reading logs written by an older build, keep that in mind.

Saving errors

When a save fails, the message shown in the browser is also written to the log, prefixed with Save failed: and carrying the exception class. You therefore have a record of the failure once the dialog has been closed, and something to look at when a user reports the problem second-hand.

It is logged at level 3, so it appears whenever Level is 3 or above — you do not have to turn the log up to 5 to see it.

Unhandled request exceptions

An exception that escapes every handler while a request is being served is logged at level 3 as Unhandled <ExceptionClass> on <path>: <message>, next to the modal dialog the browser gets.

Why this matters

Until 4.0.15 the dialog was the only trace: nothing reached the log, not even at Level: 5. Under the desktop host you at least saw the dialog; a Windows service, an ISAPI module or an Apache module left no record at all. Any diagnosis that started from "the log shows nothing between these two statements" was reading a log that could not show it.

Why a login was refused

Every refusal that is not simply a wrong password says so in the log, so a support call does not turn into guesswork. Nothing here prints a credential — see Passwords in the log.

MessageLevelMeaning
Authentication refused for user X: empty password.4A blank password was submitted. The password box is required on the page, so this normally means a scripted call
Authentication refused for user X: the user record carries no password …3The account exists but its password column is empty or NULL: it cannot be logged into. Send a temporary password with the reset flow
Authentication refused: user X is not in the user list file.4Auth: TextFile, unknown or #-disabled user
User X has no password in the user list file …3Auth: TextFile, the line carries nothing after the = — a broken user list
PIN login refused: the user record carries no SECRET_CODE …3LoginType: PIN without a per-user secret, see PIN login
Passepartout ignored: IsPassepartoutEnabled is True but PassepartoutPassword is empty …3Misconfiguration: with a value it is a master password, without one it would accept a blank password for everybody
Request blocked: the user must first complete ChangePassword. Endpoint: …4The imposed-step gate refused an endpoint outside the required view
Unauthenticated request to protected endpoint: …4The authentication gate answered 404

The rows at level 3 are the ones that mean somebody has to fix something — a user record or a configuration — rather than somebody typed the wrong password.

Check your Level before concluding that nothing happened

A message is written only when the configured Level is greater than or equal to the message's own level, and the framework default is 1. The shipped examples set detailed (4) or 5, so in practice these lines are there; an application that leaves Log/Level at the default sees none of them. Set it to at least 3 before diagnosing a login problem.

Two startup refusals are logged at level 3 and also stop the application, so they are hard to miss: an Auth: class id that nobody registered, and Auth: DBServer whose Connection block does not read the typed credentials. See Startup checks.

Logging from your own code

If you need to log information from your server-side code (custom controllers, rules, tools), include the unit EF.Logger and call the methods of TEFLogger.Instance. Kittox takes care of thread synchronization.

Remember to enable at least one logger (e.g. reference EF.Logger.TextFile in your UseKitto.pas), otherwise the logged strings have nowhere to go.

Custom loggers

You can add your own custom loggers; just have a look at the predefined ones and use them as examples and starting points.

Basically you need to create a log endpoint: create a new class inherited from TEFLogEndpoint and override the DoLog method (don't forget the initialization and finalization sections in your unit, which will make your new class available to the system).

Released under Apache License, Version 2.0.