An example of moldable logging using Beacon

This page gives a quick introduction to using Beacon for moldable logging.

The main idea is to define custom signals for capturing the start and stop of relevant actions, and create based on those simple log signals, nested high level events.

In short BeaconSignal Announcement subclass: #BeaconSignal instanceVariableNames: 'timestamp processId properties' classVariableNames: '' package: 'Beacon-Core-Signals' instances are automatically grouped into GtBeaconLogEvent GtBeaconLogBasicEvent subclass: #GtBeaconLogEvent instanceVariableNames: 'signals' classVariableNames: '' package: 'GToolkit-Utility-Logging-Core' instances using a GtBeaconEventsGrouper Object subclass: #GtBeaconEventsGrouper instanceVariableNames: 'rootEvents eventsStack shouldNotifyUpdates announcer' classVariableNames: '' package: 'GToolkit-Utility-Logging-Core' .

A useful aspect is that GtBeaconEventsCollector Object subclass: #GtBeaconEventsCollector instanceVariableNames: 'mutex logger eventsGrouper' classVariableNames: '' package: 'GToolkit-Utility-Logging-Core' can do that grouping live inside the image as signals are emitted, or we can parse the console log for Beacon signals and get exactly the same result.

For this to work it is important that Beacon signals can be fully serialisable.

Basic signals

We first need signals for modeling the start and stop of an event. We can do that with a single signal class that uses the trait TGtBeaconSignalStartEndType Trait named: #TGtBeaconSignalStartEndType instanceVariableNames: 'eventType' package: 'GToolkit-Utility-Logging-Core' , or with two different classes. For this demo we use two signal classes, namely GtMyExampleBeaconStartSignal GtMyExampleBeaconSignal subclass: #GtMyExampleBeaconStartSignal instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Utility-Logging-Examples' and GtMyExampleBeaconStopSignal GtMyExampleBeaconSignal subclass: #GtMyExampleBeaconStopSignal instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Utility-Logging-Examples' .

Starting loggers

We can manually start two loggers , one in memory and one that prints to the console.

memoryLogger := MemoryLogger  startFor: GtMyExampleBeaconStartSignal,
consoleLogger := NonInteractiveTranscriptLogger 
	startFor: GtMyExampleBeaconStartSignal,

We can also start a collector

GtMyExampleBeaconEventsCollector start

Emitting signals

Next we emit example Beacon signals. Here we also simulate nesting of signals.

1 to: 10 do: [ :anIndex |
	GtMyExampleBeaconStartSignal emit: 'Start at index ', anIndex asString.
	100 atRandom  milliSeconds wait.
	(anIndex//4)isZero ifTrue: [
		GtMyExampleBeaconStartSignal emit: 'Start subcommand at index '
			, anIndex asString.
		100 atRandom  milliSeconds wait.
		GtMyExampleBeaconStopSignal emit: 'Start subcommand at index '
			, anIndex asString ].
	GtMyExampleBeaconStopSignal emit: 'Stop at index ', anIndex asString ].
MemoryLogger reset
MemoryLogger instance.

Grouping signals

We can now manually group signals into events.

grouper := GtBeaconEventsGrouper new.
grouper processEventSignalsFor: MemoryLogger instance recordings.

We can also look at the example collector that does the grouping automatically.

GtMyExampleBeaconEventsCollector defaultInstance.

If we copy the log from the console to the clipboard we can also read the signals and create the grouping

GtMyExampleBeaconSignalsReader readFrom: Clipboard clipboardText asString

There is also an example log in case you do not have access to the console.

GtMyExampleBeaconSignalsReader readFromExample

Stopping loggers

Here we stop all previously started loggers

memoryLogger ifNotNil: [ aLogger | aLogger stop ].
consoleLogger ifNotNil: [ aLogger | aLogger stop ].
GtMyExampleBeaconEventsCollector stop