How to log Zinc events using Beacon

Zinc is a framework to deal with the HTTP networking protocol. This page gives details on how to log Zinc events.

Below is an example of a Zinc request with logging enabled, for experimenting.

rawData := ZnClient new 
	loggingOn;
	get: ('https://raw.githubusercontent.com/feenkcom/gtoolkit/v0.8.1837/.baseline-metadata.ston')
  

Logging overview

Zinc models log events through subclasses of ZnLogEvent Announcement subclass: #ZnLogEvent instanceVariableNames: 'id processId timestamp' classVariableNames: 'IdCounter LogEventAnnouncer' package: 'Zinc-HTTP-Logging' ; specific type of events are modeled using dedicated subclasses, like ZnClientRetryingEvent ZnClientLogEvent subclass: #ZnClientRetryingEvent instanceVariableNames: 'exception' classVariableNames: '' package: 'Zinc-HTTP-Logging' .

ZnClient Object subclass: #ZnClient instanceVariableNames: 'request response connection lastUsed options session logLevel newOptions' classVariableNames: '' package: 'Zinc-HTTP-Client-Server' instances can enabled logging using:

- ZnClient>>#loggingOn loggingOn "Turn full logging on - generate all log events" self logLevel: 3 for enabling all log events, or using

- ZnClient>>#logLevel: logLevel: integer "Set the log level to integer. 0 - no logging 1 - simplified transaction logging 2 - detailed transaction logging 3 - log everything" logLevel := integer for controling the log level.

The class side of ZnLogEvent Announcement subclass: #ZnLogEvent instanceVariableNames: 'id processId timestamp' classVariableNames: 'IdCounter LogEventAnnouncer' package: 'Zinc-HTTP-Logging' maintains a singleton announcer, accessed through ZnLogEvent>>#announcer announcer ^ LogEventAnnouncer ifNil: [ LogEventAnnouncer := Announcer new ] , that is used to announce all log events. Consumers interested in log events can register with that announcer.

ZnLogEvent announcer 
	when: ZnLogEvent 
	do: [ :event | 
		self inform: 'Zinc Log: ', event printString ].
  

This is a global announcer. The subscription remains there until explicitly removed.

A different subclass of ZnLogEvent Announcement subclass: #ZnLogEvent instanceVariableNames: 'id processId timestamp' classVariableNames: 'IdCounter LogEventAnnouncer' package: 'Zinc-HTTP-Logging' can be used to listen only for events of a given type.

Direct logging to transcript

The simples way to log all Zinc events is using ZnLogEvent>>#logToTranscript logToTranscript self stopLoggingToTranscript. ^ self announcer when: ZnLogEvent do: [ :event | self crTrace: event ] for: self . That registers a consumer for logging announcements and prints them to the transcript. It does not use Beacon, but directly prints announcements.

ZnLogEvent logToTranscript
  

Direct logging with Beacon

The first and simplest way to use Beacon with Zinc log events is through ZnLogEvent>>#logToBeacon logToBeacon self stopLoggingToBeacon. ^ self announcer when: ZnLogEvent do: [ :event | (ZnLogEventSignal on: event) emit ] for: self . This captures all log events raised by Zinc and converts them to Beacon signals, by wrapping them in an instance of ZnLogEventSignal BeaconSignal subclass: #ZnLogEventSignal instanceVariableNames: 'target' classVariableNames: '' package: 'Beacon-Zinc' .

ZnLogEvent logToBeacon.
  

We can the work with any Beacon logger to handle these signals; for example a MemoryLogger SignalLogger subclass: #MemoryLogger instanceVariableNames: 'recordings announcer mutex interestingAnnouncements' classVariableNames: 'WriteFilename WritePeriod WriteProcess' package: 'Beacon-Core-Loggers' to save the signals in memory, or a NonInteractiveTranscriptLogger SignalLogger subclass: #NonInteractiveTranscriptLogger instanceVariableNames: '' classVariableNames: '' package: 'Beacon-Core-Loggers' logger do directly print siglans to stdout.

MemoryLogger startFor: ZnLogEventSignal.
  

To filter for particular types of announcements we can use a custom condition:

MemoryLogger startFor: (ZnLogEventSignal where: [ :aSignal |
	aSignal target isKindOf: ZnClientLogEvent]).
  
MemoryLogger stop
  
MemoryLogger reset.
  
MemoryLogger instance
  

Using a custom Beacon

The second, and more complex way to handle Zinc log events using Beacon, is to create a new Beacon Object subclass: #Beacon instanceVariableNames: 'announcer' classVariableNames: 'instance' package: 'Beacon-Core-Beacon' instance that directly listens for announcement announced by ZnLogEvent>>#announcer announcer ^ LogEventAnnouncer ifNil: [ LogEventAnnouncer := Announcer new ] .

In this case the log announcements from Zinc are directly used as Beacon signals without any conversion.

beacon := Beacon new 
	announcer: ZnLogEvent announcer
  

The logger that we use next needs to explicitly listed to the Beacon instance we previously created.

logger := MemoryLogger new 
	beacon: beacon;
	startFor: ZnClientLogEvent
  
logger stop.
  
logger reset