Eliza 17 - Logging

by Ravi Bhavnani


It’s useful to be able to track how a complex program like Eliza works. It’s particularly important to know how Eliza decides to display a specific response. Having the ability to easily follow Eliza’s inner working in real time will enable us to improve Eliza if we discover a flaw in its logic.

Complex programs trace their execution by using a logger, which is a component that allows a program to log (i.e. record) interesting events such as important decisions or errors. In this step, we’ll implement a logger and provide the ability for the user to turn on and turn off logging, so that they can view Eliza’s logic while having a conversation.

Defining the logger

A logger essentially provides the ability to:

  1. Log an information message (e.g. “App is starting...”).
  2. Log a warning message (e.g. “Unrecognized response encountered”).
  3. Log an error message (e.g. “Initialization failure occured”).
  4. Turn on and turn off logging.

Let’s start by defining an interface that presents this behavior. We’ll call it (what else) ILogger.

At this point, we may be tempted to write a Logger class that implements ILogger. Let’s hold off doing that for now. After all, the interface already tells Eliza everything it needs to know for it to be able to use a logger. As long as the driver program gives Eliza a concrete implementation of an ILogger when it runs, Eliza can use that to log messages.

Using the logger

If you search the code of the Eliza project for the string:

    Console.WriteLine

you’ll find a few (5, to be precise) commented lines of code that trace Eliza’s reasoning process. If you uncomment these lines and run Eliza, you’ll see the messages that Eliza logs as it runs. Here’s an example:

In our version of Eliza, messages are logged by writing them to the console using Console.WriteLine(), because Eliza is a console (command line) application. But wait a minute! The Eliza class isn’t an application - it’s simply an object that happens to be used by the console application, ElizaMain.

Nothing prevents Eliza from being used by a Windows application or even an Android app. Well, nothing except this horrible reliance on Console.WriteLine(). Remember, Windows and Android have no idea what a Console is. So if we want Eliza to (eventually) be usable on other platforms, we’ll need to replace the calls to Console.WriteLine() with something that’s supported on those platforms.

Thankfully, we already have a logging mechanism that runs in console, Windows and Android apps: it’s called ILogger! What this means is:

  1. We’ll give Eliza an instance of an ILogger (suitable for the platform on which it’s running).
  2. We’ll replace the calls to Console.WriteLine() with ILogger methods.

Giving Eliza an ILogger

In order for Eliza to use an ILogger, we need to give it one. The best way to do this is pass it an ILogger in its constructor.

Eliza will store this logger in a private variable and use it whenever it needs.

Let’s also provide Eliza the ability to turn on and turn off logging at any time during a conversation. We do this by adding this method to the IEliza interface:

and a corresponding implementation to the Eliza class. Notice how Eliza simply delegates this task to its logger.

Now that Eliza has a logger, let’s use make use of it. We’ll replace all the calls to Console.WriteLine() (that only work in the world of console applications) with calls to ILogger methods, that are guaranteed to work on all platforms. One such call is:

which becomes:

There’s another class that does logging, and that’s DecompReassemblyRule, which logs its actions in its CanDecompose() method.

In order for this method to also use an ILogger, it needs to receive one. So let’s pass the method an ILogger.

This will require us to also tweak the Pattern, FormatFreePattern and ComplexPattern classes. When this is done, Eliza will be ready to use its ILogger instead of calling Console.WriteLine().

What remains is for the driver program ElizaMain (a console app) to pass an ILogger to Eliza’s constructor. So let’s do this.

An ILogger for ElizaMain

ElizaMain is a console app. In order to view Eliza’s log messages, it needs to give Eliza an ILogger that works in the world of console apps. So let’s create one. We’ll call it ConsoleLogger and add it to the ElizaMain project.

How does ConsoleLogger work?

STOP. TRY AND WRITE ConsoleLogger YOURSELF. WHEN DONE, OR IF YOU'RE STUCK, TAKE A LOOK AT THE VERSION IN THE SOLUTION.

We’ll also need to create a similar ConsoleLogger for the ElizaTest project.

Enabling logging during a conversation

Now that we’ve implemented logging, the only thing that remains is giving the user the means to turn logging on and off during a conversation, so they can view Eliza’s logic in real time. This means we need to expose the ILogger.EnableLogging() method to the user.

We’ll do this by recognizing a couple of commands issued by the user that aren’t part of the conversation. We’ll differentiate commands from normal user input by requiring them to be prefixed with the $ symbol. For now, we’ll recognize these two commands:

    $LON
    $LOFF

that represent “turn on logging” and “turn off logging”. This is done by slightly modifying the the ElizaMain’s main input/output loop.

Entering $LON or $LOFF in the midst of a conversation will now cause Eliza to display (or hide) log messages, as seen here.

Where we’ve reached

In this step, we accomplished two important goals:

  1. We made it possible for the user to view Eliza’s thinking process as it conducts a conversation.
  2. In doing so, we made the Eliza engine no longer limited to running only within a console app.

Next steps

In the next step, we’ll give Eliza the ability to respond to the powerful emotions of love and hate.  Or at least the illusion of being able to respond to these emotions.

 

Most of the content at this site is copyright © Ravi Bhavnani.
Questions or comments?  Send mail to ravib@ravib.com