1 Introduction
1.1 Features
1.2 Easy to Add
1.3 See a Demo
2 User Interface
2.1 When Changing or Resizing Terminals
2.2 Setting What to Capture and View
2.3 Debugging
2.4 Quitting
2.5 Handling Log Flood
3 Programming Interface
program-rackonsole-title
hostname-rackonsole-title
program-on-hostname-rackonsole-title
rackonsole
4 Known Issues
5 History
6 Legal
Version: 1:0

Rackonsole: Lightweight Operator Console for Racket Server Processes

Neil Van Dyke

 (require (planet neil/rackonsole:1:0))

1 Introduction

The Rackonsole package provides an easy way to add a user interface for system operators to server processes implemented in Racket. This interface may be run within a detachable tmux or GNU Screen session, such as when accessing a cloud server via SSH.

ProTip: In 2012, spelling “server” as “cloud server” gets you more money.

Rackonsole is intended to run for GNU/Linux, and similar Unix-like systems. It works with terminals supported by the charterm package. A Rackonsole user interface can be accessed from Apple Macintosh and Microsoft Windows systems as well, if they are running compatible terminals (such as in SSH programs, terminal emulators, or some “terminal” or “command” windows.

1.1 Features

Rackonsole currently provides the following features to the operator:
  • View logging information from the application, including ability to change both what levels of log messages are captured and which are displayed on the screen. So, for example, Rackonsole might be capturing all log levels at the moment, but the operator can temporarily narrow the display to only errors. The operator can also increase and lower the level of messages captured dynamically, to adjust the balance between information and performance.

  • Quit the application in a manner specified by the developer, rather than merely Ctrl-C-ing or sending other signals that might not cause an orderly shutdown. The application can specify a shutdown procedure in the code, in the call to rackonsole.

  • Generate debugging information to provide to a developer who does not have access to the server. In the current version, this is via gdbdump.

  • A sense that the application is running. Also, by default, the title includes the application name and server name, for ease when dealing with multiple applications and servers.

Rackonsole may be used in conjunction with the PLTSYSLOG environment variable, with racksonsole providing an easy display of current activity of a process, and Syslog providing centralized and long-term logging.

1.2 Easy to Add

Adding Rackonsole to an existing application can be done in a couple lines of code, depending on how you count lines of code. Basically, you add a require for the Rackonsole PLaneT package, and you apply the rackonsole procedure in a thread near the start of your program. For example, if your application looks like this:

"myserver.rkt"

#lang racket
(require "myinternals.rkt")
 
(for ((request (my-start-server)))
  (with-handlers
      ((exn:fail?
        (lambda (exn)
          (log-error (string-append "Request failed: "
                                    (exn-message exn))))))
    (my-handle-request request)))
Then, if you just want the default options for Rackonsole, you can simply add a require and a call to start racksonsole in a thread.

Talk about rapid agile development!

"myserver.rkt"

#lang racket
(require "myinternals.rkt"
         (planet neil/rackonsole))
 
(thread rackonsole)
 
(for ((request (my-start-server)))
  (with-handlers
      ((exn:fail?
        (lambda (exn)
          (log-error (string-append "Request failed: "
                                    (exn-message exn))))))
    (my-handle-request request)))
If you want to set some options, such as a quit procedure, changing the default capture level to include warning messages, and the identifying title to be displayed on the Rackonsole screen, it’s only slightly more complicated:

"myserver.rkt"

#lang racket
(require "myinternals.rkt"
         (planet neil/rackonsole))
 
(thread
 (lambda ()
    (rackonsole #:title         "MyApp 2000"
                #:capture-level 'warning
                #:quit-proc     (lambda ()
                                  (display "Farewell!\n")
                                  (exit)))))
 
(for ((request (my-start-server)))
  (with-handlers
      ((exn:fail?
        (lambda (exn)
          (log-error (string-append "Request failed: "
                                    (exn-message exn))))))
    (my-handle-request request)))
That’s pretty much all you have to do (or can do, for that matter).

1.3 See a Demo

You can install Rackonsole and run a demonstration of it with the command:
  racket -W none -p neil/rackonsole/demo
Following sections of this documentation describe how to operate Rackonsole, and provide details of the programming interface.

2 User Interface

The Rackonsole user interface has a few parts:
  • Title The Title is usually the upper-left corner, in reverse-video, and usually identifies the application and/or server.

  • Status The Status is usually the upper-right corner, and displays the current state of the capture level and view level. (If the terminal is not wide enough to put both the Title and Status on the same row, such as if the Title is long, then both are centered on their own rows.)

  • Menu The Menu is centered below the Title and Status, and usually underlined. It identifies which menu it is, and shows a list of keys that can be pressed, with each key surrounded by square brackets. Menus that are not the Main menu can generally be escaped out of by pressing the - (minus), Backspace, Esc key. (Additionally, the Quit menu is escaped by any key that is not the Y key, to decrease the likelihood of quitting the application accidentally.)

  • Log View The Log View takes the rest of the screen. The most recent captured log entries corresponding to the view level are displayed here, with the most recent entries at the top. As new entries are captured and viewed, older entries scroll off the bottom of the screen (but might be viewed again later by restricting the view level). Entries with 'error level and higher are in boldface on terminals supporting that. Each entry is truncated to the width of the terminal.

The following subsections describe operation in terms of tasks.

2.1 When Changing or Resizing Terminals

Did we mention we do cloud $erver$.

When the terminal is changed, such as when reattaching a Screen or tmux session, or when resizing an XTerm, you can select [R]edraw from the Main menu to detect the current terminal size and redraw.
(Note that Rackonsole technically could detect terminal changes without needing to press the R key, but that would increase the additional load on the system, potentially slowing responsiveness of the main server process.)

2.2 Setting What to Capture and View

The capture level specifies the log level of messages to capture. The view level specifies the level of messages to view currently. They are changed from the [C]apture and [V]iew items of the Main menu, to go to the Capture or View menu.
On the Capture and View menus, the options are abbreviated: [N] for none, and [F] through [D] for 'fatal through 'debug.
Note that adjusting the view level to a lower level can cause messages previously captured but not viewed to be displayed.
Note that, the lower the capture level, the more resources the application might use. For example, your application might leave log-debug forms not commented-out, and if any log receiver, such as Rackonsole, registers interest in 'debug messages, then the application does additional work to generate and send those messages.

2.3 Debugging

Currently, Rackonsole has only one debugging option: to run the gdbdump tool to get native stack traces of native threads. This might be useful if you suspect a system-level problem, such as in system calls.
You can perform this by starting at the Main menu, and selecting [D]ebug and then [G]dbdump. Then (assuming the application has not overridden gdbdump) wait 10 seconds, and get the file, which likely will be in "/var/tmp/gdbdump". Rackonsole itself will freeze for the 10 seconds, to try to increase the likelihood that the native dump will capture information about the more interesting main application rather than Rackonsole. The main application should pause only briefly, if noticeably at all.

2.4 Quitting

To quit the application, select [Q]uit from the Main menu, then select [Y]es. Rackonsole will clear the screen and restore the terminal to a normal state, and then execute any special quit procedure that the application specified.

2.5 Handling Log Flood

If the log is being flooded, such as if the application is having a bad day, you can temporarily set the capture level to [N] (none), to potentially decrease the logging load on the application. Then you might wish to adjust the view level to see the pertinent messages, and then resolve the problem with the application.

3 Programming Interface

The main interface is the rackonsole procedure.
One important thing to note: by default, Racket will write all messages level 'error and higher from the default logger to stderr, which will usually go to the same TTY that Rackonsole is using, corrupting the display a bit. So, you will want to either disable this logging to stderr (with the -W none command line option to racket, or by setting the PLTSTDERR environment variable of the racket process to none), or create a new current-logger (to which your application writes, and which is monitored by Rackonsole).
(program-rackonsole-title)  string?
(hostname-rackonsole-title)  string?
(program-on-hostname-rackonsole-title)  string?
These procedures can be used for the #:title argument of rackonsole. You can also use them as part of your own procedure, such as:
(lambda ()
  (string-append "MyApp on "
                 (hostname-rackonsole-title)))
Note that the program name as detected by these procedures will often be "racket" unless the -N command line argument to racket is used.
(rackonsole [#:tty tty    
  #:title title    
  #:logger logger    
  #:log-size log-size    
  #:capture-level capture-level    
  #:view-level view-level    
  #:quit-proc quit-proc])  void?
  tty : (or/c #f path-string?) = #f
  title : (or/c #f string?) = #f
  logger : logger? = (current-logger)
  log-size : exact-positive-integer? = 1000
  capture-level : (or/c #f 'fatal 'error 'warning 'info 'debug)
   = 'error
  view-level : (or/c #f 'fatal 'error 'warning 'info 'debug)
   = 'debug
  quit-proc : (-> any) = #f
This is the main procedure of Rackonsole. You usually want to start it in its own thread. All arguments are optional.
#:tty is the TTY to use, and defaults to "/dev/tty". You probably don’t need to change this.
#:title is the title to display on the screen. By default, this is “program on server.” For example: “myprogram on myserver
#:logger is the logger to use. Defaults to (current-logger).
#:log-size is the number of lines of captured log messages to store in a ring buffer. Default is 1000.
#:capture-level is the capture level, which is either the usual Racket symbol or #f for none. Default is 'error.
#:view-level is the view level. Default is 'error.
#:quit-proc is a thunk to apply after the operator quits the application via the user interface, or #f for none. If non-#f, this is applied after Rackonsole has cleared the screen and restored the terminal.
The rackonsole procedure normally returns only when the application is quit from the user interface.

4 Known Issues

5 History

6 Legal

Copyright 2012 Neil Van Dyke. This program is Free Software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See http://www.gnu.org/licenses/ for details. For other licenses and consulting, please contact the author.