2:3
rackonsole: Lightweight Operator Console for Server Processes
Link to this document with
@other-doc['(lib "rackonsole/rackonsole.scrbl")]
Link to this document with
@other-doc['(lib "rackonsole/rackonsole.scrbl")]
1 Introduction
Link to this section with
@secref["Introduction" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Introduction" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Features" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Features" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Easy_to_Add" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Easy_to_Add" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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" |
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" |
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
Link to this section with
@secref["See_a_Demo" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["See_a_Demo" #:doc '(lib "rackonsole/rackonsole.scrbl")]
After installing the rackonsole package, you can run a demonstration of it with the command:
racket -W none -em "(require rackonsole/demo)"
Following sections of this documentation describe how to operate rackonsole, and provide details of the programming interface.
2 User Interface
Link to this section with
@secref["User_Interface" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["User_Interface" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["When_Changing_or_Resizing_Terminals"
#:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["When_Changing_or_Resizing_Terminals"
#:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Setting_What_to_Capture_and_View"
#:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Setting_What_to_Capture_and_View"
#:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Debugging" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Debugging" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Quitting" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Quitting" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Handling_Log_Flood" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Handling_Log_Flood" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Programming_Interface" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Programming_Interface" #:doc '(lib "rackonsole/rackonsole.scrbl")]
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
Link to this section with
@secref["Known_Issues" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Known_Issues" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Add a UI menu item to force a GC.
Does not yet provide a way to scroll arbitrarily through older
messages in the ring buffer, short of making the terminal screen taller or limiting the view level.
Currently truncates each message at the width of the terminal
screen, without providing a way to see all of longer messages, short of making
the terminal screen wider or going to the Syslog.
We should add in better handling of unprintable characters in log messages.
Maybe detect duplicate adjacent events and log them in a “last
message repeated N times” manner.
If you get a flood of logging events, having any kind of log
receiver in place can increase the load on the system, mainly by the events
being buffered by Racket indefinitely and increasing memory usage. We might
add a feature by which Rackonsole detects a flood and backs off for a while,
such as by discarding events, or even detaching itself as a receiver. Note,
however, that the way Rackonsole handles I/O keeps its menus responsive even in
event of flood.
We could make the Rackonsole menus adapt to very small displays,
such as on smartphone SSH clients, by automatically abbreviating.
Rackonsole could use a cooler name, but not so cool as to be pretentious.
5 History
Link to this section with
@secref["History" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["History" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Version 2:3 — 2016-03-01
Version 2:2 — 2016-02-29
Version 2:1 — 2016-02-27
Version 2:0 — 2016-02-26
Version 1:0 — 2012-06-28
6 Legal
Link to this section with
@secref["Legal" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Link to this section with
@secref["Legal" #:doc '(lib "rackonsole/rackonsole.scrbl")]
Copyright 2012, 2016 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.