diff --git a/documentation/UserGuide.md b/documentation/UserGuide.md index 715e670..69257f0 100644 --- a/documentation/UserGuide.md +++ b/documentation/UserGuide.md @@ -11,15 +11,16 @@ For specific cases, a specialized logger can be used. - [Add sub-loggers to your `TinyLogger`](#add-sub-loggers-to-your-tinylogger) - [Remove sub-loggers](#remove-sub-loggers) - [List the sub-loggers](#list-the-sub-loggers) - - [Further configurations](#further-configurations) - - [Configure the timestamp](#configure-the-timestamp) - - [Configure the identation string](#configure-the-identation-string) - [Record with your logger](#record-with-your-logger) - [Record a single line log](#record-a-single-line-log) - [Recording the execution of a task](#recording-the-execution-of-a-task) - [Lazy recording](#lazy-recording) - [Use a logger other than the global logger](#use-a-logger-other-than-the-global-logger) - [Clear your logger](#clear-your-logger) + - [Further configurations](#further-configurations) + - [Configure the timestamp](#configure-the-timestamp) + - [Configure the identation string](#configure-the-identation-string) + - [Add extra indentation block](#add-extra-indentation-block) - [Use special logger for tests](#use-special-logger-for-tests) @@ -115,51 +116,6 @@ If you with to know all the loggers of a kind, you can use: * `transcriptLoggers` * `stdoutLoggers` -### Further configurations - -#### Configure the timestamp - -By default, the preamble of the log will be a timestamp with a human readable format, e.g.: - -``` -2018-11-29T23:19:55.511775+01:00: Test -``` - -But this format is configurable. The `timestampFormatBlock:` method can be used with a parameter that is a block taking a stream as parameter and the timestamp (instance of `DateAndTime`) and use that to write the preamble on the stream. - -```Smalltalk -TinyLogger default - timestampFormatBlock: [ :aStream :timestamp | - timestamp asDate printOn: aStream. - aStream << ' '. "Cannot use #space because of Stdio streams" - timestamp asTime print24: true on: aStream ] -``` - -This will produce logs of this format: - -``` -29 November 2018 00:06:30: Test -``` - -#### Configure the identation string - -By default using #`execute:recordedAs:` will use a tab for identation. It is possible to configure this using `#identationString:` to have, for example, spaces. - -```Smalltalk -TinyLogger default identationString: ' '. "Two spaces" -self execute: [ 'Log' record ] recordedAs: 'Task' -``` - -Will produce a log like this: - -``` -2018-11-29T23:21:04.897775+01:00: Begin: Task -2018-11-29T23:21:04.900775+01:00: Log -2018-11-29T23:21:04.909775+01:00: End: Task -``` - -On the second line, the identation will use two spaces instead of a tab that is the default value. - ## Record with your logger This section will cover the API to record information. @@ -189,13 +145,13 @@ self execute: [ 1 to: 5 do: [ :value | value asString record ] ] recordedAs: 'Ta Will produce a log like this: ``` -2018-11-29T23:21:04.897775+01:00: Begin: Task with only one nesting. -2018-11-29T23:21:04.900775+01:00: 1 -2018-11-29T23:21:04.902775+01:00: 2 -2018-11-29T23:21:04.904775+01:00: 3 -2018-11-29T23:21:04.906775+01:00: 4 -2018-11-29T23:21:04.908775+01:00: 5 -2018-11-29T23:21:04.909775+01:00: End: Task with only one nesting. +2018-11-29T23:21:04.897775+01:00: Begin: Task with only one nesting. +2018-11-29T23:21:04.900775+01:00: 1 +2018-11-29T23:21:04.902775+01:00: 2 +2018-11-29T23:21:04.904775+01:00: 3 +2018-11-29T23:21:04.906775+01:00: 4 +2018-11-29T23:21:04.908775+01:00: 5 +2018-11-29T23:21:04.909775+01:00: End: Task with only one nesting. ``` It is also possible to nest them: @@ -213,26 +169,26 @@ self execute: [ It will produce this kind of output: ``` -2018-11-29T23:21:20.147775+01:00: Begin: My first nest -2018-11-29T23:21:20.151775+01:00: Begin: My second nest -2018-11-29T23:21:20.153775+01:00: 1 -2018-11-29T23:21:20.155775+01:00: End: My second nest -2018-11-29T23:21:20.157775+01:00: Begin: My second nest -2018-11-29T23:21:20.158775+01:00: 1 -2018-11-29T23:21:20.160775+01:00: 2 -2018-11-29T23:21:20.161775+01:00: End: My second nest -2018-11-29T23:21:20.163775+01:00: Begin: My second nest -2018-11-29T23:21:20.164775+01:00: 1 -2018-11-29T23:21:20.165775+01:00: 2 -2018-11-29T23:21:20.167775+01:00: 3 -2018-11-29T23:21:20.169775+01:00: End: My second nest -2018-11-29T23:21:20.171775+01:00: Begin: My second nest -2018-11-29T23:21:20.172775+01:00: 1 -2018-11-29T23:21:20.175775+01:00: 2 -2018-11-29T23:21:20.176775+01:00: 3 -2018-11-29T23:21:20.177775+01:00: 4 -2018-11-29T23:21:20.179775+01:00: End: My second nest -2018-11-29T23:21:20.180775+01:00: End: My first nest +2018-11-29T23:21:20.147775+01:00: Begin: My first nest +2018-11-29T23:21:20.151775+01:00: Begin: My second nest +2018-11-29T23:21:20.153775+01:00: 1 +2018-11-29T23:21:20.155775+01:00: End: My second nest +2018-11-29T23:21:20.157775+01:00: Begin: My second nest +2018-11-29T23:21:20.158775+01:00: 1 +2018-11-29T23:21:20.160775+01:00: 2 +2018-11-29T23:21:20.161775+01:00: End: My second nest +2018-11-29T23:21:20.163775+01:00: Begin: My second nest +2018-11-29T23:21:20.164775+01:00: 1 +2018-11-29T23:21:20.165775+01:00: 2 +2018-11-29T23:21:20.167775+01:00: 3 +2018-11-29T23:21:20.169775+01:00: End: My second nest +2018-11-29T23:21:20.171775+01:00: Begin: My second nest +2018-11-29T23:21:20.172775+01:00: 1 +2018-11-29T23:21:20.175775+01:00: 2 +2018-11-29T23:21:20.176775+01:00: 3 +2018-11-29T23:21:20.177775+01:00: 4 +2018-11-29T23:21:20.179775+01:00: End: My second nest +2018-11-29T23:21:20.180775+01:00: End: My first nest ``` ## Lazy recording @@ -278,6 +234,76 @@ Each logger understands the method `#clearLog`. This method will have as effect TinyLogger default clearLogger ``` +## Further configurations + +### Configure the timestamp + +By default, the preamble of the log will be a timestamp with a human readable format, e.g.: + +``` +2018-11-29T23:19:55.511775+01:00: Test +``` + +But this format is configurable. The `timestampFormatBlock:` method can be used with a parameter that is a block taking a stream as parameter and the timestamp (instance of `DateAndTime`) and use that to write the preamble on the stream. + +```Smalltalk +TinyLogger default + timestampFormatBlock: [ :aStream :timestamp | + timestamp asDate printOn: aStream. + aStream << ' '. "Cannot use #space because of Stdio streams" + timestamp asTime print24: true on: aStream ] +``` + +This will produce logs of this format: + +``` +29 November 2018 00:06:30: Test +``` + +### Configure the identation string + +By default using #`execute:recordedAs:` will use a tab for identation. It is possible to configure this using `#identationString:` to have, for example, spaces. + +```Smalltalk +TinyLogger default identationString: ' '. "Two spaces" +self execute: [ 'Log' record ] recordedAs: 'Task' +``` + +Will produce a log like this: + +``` +2018-11-29T23:21:04.897775+01:00: Begin: Task +2018-11-29T23:21:04.900775+01:00: Log +2018-11-29T23:21:04.909775+01:00: End: Task +``` + +On the second line, the identation will use two spaces instead of a tab that is the default value. + +### Add extra indentation block + +Depending on the preferences of the developper it is possible to use #`indentExecutionBlock` to add an extra indentation to the block of `#execute:recordedAs:`. + +```Smalltalk +TinyLogger default indentExecutionBlock: true. +self execute: [ 'Log' record ] recordedAs: 'Task' +``` + +Will produce a log like this: + +``` +2018-11-29T23:21:04.897775+01:00: Begin: Task +2018-11-29T23:21:04.900775+01:00: Log +2018-11-29T23:21:04.909775+01:00: End: Task +``` + +Instead of + +``` +2018-11-29T23:21:04.897775+01:00: Begin: Task +2018-11-29T23:21:04.900775+01:00: Log +2018-11-29T23:21:04.909775+01:00: End: Task +``` + ## Use special logger for tests It is probable that you might not want to have your default logger for tests. It is possible to archive this by overriding the #performTest method of your TestCase like this: diff --git a/src/TinyLogger-Tests/TinyLoggerTest.class.st b/src/TinyLogger-Tests/TinyLoggerTest.class.st index 7e4c262..f02872f 100644 --- a/src/TinyLogger-Tests/TinyLoggerTest.class.st +++ b/src/TinyLogger-Tests/TinyLoggerTest.class.st @@ -191,9 +191,9 @@ TinyLoggerTest >> testExecuteRecordedAs2 [ self assert: contents withUnixLineEndings equals: - 'No time: Begin: This is a new test -No time: test -No time: End: This is a new test + 'No time: Begin: This is a new test +No time: test +No time: End: This is a new test ' withUnixLineEndings ] ensure: [ Stdio recoverFromGHMutation. stream close ] @@ -245,11 +245,11 @@ TinyLoggerTest >> testExecuteRecordedAsKeepRightIndentation [ contents := Stdio stdout contents asString. "Ensure we have the right indentation." self assert: errorDetected. - self assert: contents withUnixLineEndings equals: 'No time: Begin: This is a new test -No time: End with error: This is a new test. Error message: "Error: test" -No time: Begin: This is a new test -No time: test -No time: End: This is a new test + self assert: contents withUnixLineEndings equals: 'No time: Begin: This is a new test +No time: End with error: This is a new test. Error message: "Error: test" +No time: Begin: This is a new test +No time: test +No time: End: This is a new test ' withUnixLineEndings ] ensure: [ Stdio recoverFromGHMutation. stream close ] @@ -341,10 +341,10 @@ TinyLoggerTest >> testNestedExecuteRecordedAs [ contents := Stdio stdout contents asString. self assert: bool1. self assert: bool2. - self assert: (contents includesSubstring: ' Begin: Test1'). - self assert: (contents includesSubstring: ' End: Test1'). - self assert: (contents includesSubstring: ' Begin: Test2'). - self assert: (contents includesSubstring: ' End: Test2') ] + self assert: (contents includesSubstring: 'Begin: Test1'). + self assert: (contents includesSubstring: 'End: Test1'). + self assert: (contents includesSubstring: ' Begin: Test2'). + self assert: (contents includesSubstring: ' End: Test2') ] ensure: [ Stdio recoverFromGHMutation. stream close ] ] @@ -562,3 +562,58 @@ TinyLoggerTest >> testWithDefaultLoggers [ "Ensure the loggers are reset when this method is called" self assert: logger loggers size equals: numberOfDefaultLoggers ] + +{ #category : 'tests' } +TinyLoggerTest >> testindentExecutionBlock [ + | contents stream | + logger + timestampFormatBlock: [ :s | s nextPutAll: 'No time' ]; + removeAllLoggers; + addStdoutLogger; + indentExecutionBlock: true. + stream := '' writeStream. + [ Stdio stub stdout willReturn: stream. + Object new execute: [ 'test' record ] recordedAs: 'This is a new test'. + contents := Stdio stdout contents asString. + + "Ensure we have the right indentation." + self + assert: contents withUnixLineEndings + equals: + 'No time: Begin: This is a new test +No time: test +No time: End: This is a new test +' withUnixLineEndings ] + ensure: [ Stdio recoverFromGHMutation. + stream close ] +] + +{ #category : 'tests' } +TinyLoggerTest >> testindentExecutionBlockKeepRightIndentation [ + + | contents stream errorDetected | + errorDetected := false. + logger + timestampFormatBlock: [ :s | s nextPutAll: 'No time' ]; + removeAllLoggers; + addStdoutLogger; + indentExecutionBlock: true. + stream := '' writeStream. + [ + Stdio stub stdout willReturn: stream. + [ Object new execute: [ Error signal: 'test' ] recordedAs: 'This is a new test' ] + on: Error + do: [ errorDetected := true ]. + Object new execute: [ 'test' record ] recordedAs: 'This is a new test'. + contents := Stdio stdout contents asString. + "Ensure we have the right indentation." + self assert: errorDetected. + self assert: contents withUnixLineEndings equals: 'No time: Begin: This is a new test +No time: End with error: This is a new test. Error message: "Error: test" +No time: Begin: This is a new test +No time: test +No time: End: This is a new test +' withUnixLineEndings ] ensure: [ + Stdio recoverFromGHMutation. + stream close ] +] diff --git a/src/TinyLogger/TinyAbstractLogger.class.st b/src/TinyLogger/TinyAbstractLogger.class.st index 7d9ee61..ae4be5e 100644 --- a/src/TinyLogger/TinyAbstractLogger.class.st +++ b/src/TinyLogger/TinyAbstractLogger.class.st @@ -44,6 +44,13 @@ TinyAbstractLogger >> clearLog [ self subclassResponsibility ] +{ #category : 'accessing' } +TinyAbstractLogger >> indentExecutionBlock [ + + + ^ self subclassResponsibility +] + { #category : 'accessing' } TinyAbstractLogger >> indentationString [ diff --git a/src/TinyLogger/TinyLeafLogger.class.st b/src/TinyLogger/TinyLeafLogger.class.st index 4c38298..e1466ca 100644 --- a/src/TinyLogger/TinyLeafLogger.class.st +++ b/src/TinyLogger/TinyLeafLogger.class.st @@ -56,6 +56,12 @@ TinyLeafLogger >> depth [ ^ self parentLogger depth ] +{ #category : 'accessing' } +TinyLeafLogger >> indentExecutionBlock [ + + ^ self parentLogger indentExecutionBlock +] + { #category : 'accessing' } TinyLeafLogger >> indentationString [ diff --git a/src/TinyLogger/TinyLogger.class.st b/src/TinyLogger/TinyLogger.class.st index 75616e2..7256ed2 100644 --- a/src/TinyLogger/TinyLogger.class.st +++ b/src/TinyLogger/TinyLogger.class.st @@ -21,7 +21,8 @@ Public API and Key Messages - #addFileLoggerNamed: Add a logger on a file whose name is passed as parameter - #ensure: Variant of all previous #addX message. This one will add the new logger only if there is not equivalent logger already present - #timestampFormatBlock: Give as parameter a block taking a stream as parameter and writing the timestamp you want -- #identationString: Allow to customize the identation string. By default it is a tab, but you can use spaces instead. +- #indentationString: Allow to customize the identation string. By default it is a tab, but you can use spaces instead. +- #indentExecutionBlock: Allow to add an extra indentation to block from #execute:recordedAs: . Examples -------------------- @@ -63,7 +64,8 @@ Examples ""Change the default timestamp format or identation string"" TinyLogger default timestampFormatBlock: [ :aStream :timestamp | timestamp asDate printOn: aStream. aStream << ' '. ""Cannot use #space because of Stdio streams"" timestamp asTime print24: true on: aStream ]; - identationString: ' '. + identationString: ' '; + indentExecutionBlock: true. ``` Internal Representation and Key Implementation Points. @@ -73,7 +75,8 @@ Internal Representation and Key Implementation Points. depth: I record the depth level of the nesting. loggersMap: I am used to store the loggers. I keep for each kind of loggers a collection of their instances. timestampFormatBlock: I am a block defining the way the timestamp should be written. - identationString I am a String used to ident logs. + identationString: I am a String used to ident logs. + indentExecutionBlock: Allow to add an extra indentation to block from #execute:recordedAs: . " Class { @@ -83,7 +86,8 @@ Class { 'timestampFormatBlock', 'indentationString', 'depth', - 'loggersMap' + 'loggersMap', + 'indentExecutionBlock' ], #classVars : [ 'Default' @@ -195,25 +199,24 @@ TinyLogger >> execute: aBlock recordedAs: aBlockOrString [ ifTrue: [ aBlockOrString value ] ifFalse: [ aBlockOrString ]. self hasLoggers ifFalse: [ ^ aBlock cull: logMessage ]. - - self increaseDepthLevel. + self indentExecutionBlock ifTrue: [ self increaseDepthLevel ]. self record: 'Begin: ' , logMessage. self increaseDepthLevel. [ - [ result := aBlock cull: logMessage ] - on: Error - do: [ :exception | "If there is an error, we keep the message and pass it. The message will be used in the #ifCurtailed: to ensure we keep the right indentation and print a better result to the user." - errorMessage := exception printString. - exception pass ] ] ifCurtailed: [ "If there is an unexpected termination of the execution, print that there was an error." - self decreaseDepthLevel. - self record: 'End with error: ' , logMessage , '.' , (errorMessage - ifNil: [ '' ] - ifNotNil: [ ' Error message: "' , errorMessage , '"' ]). - self decreaseDepthLevel ]. + [ result := aBlock cull: logMessage ] + on: Error + do: [ :exception | "If there is an error, we keep the message and pass it. The message will be used in the #ifCurtailed: to ensure we keep the right indentation and print a better result to the user." + errorMessage := exception printString. + exception pass ] ] ifCurtailed: [ "If there is an unexpected termination of the execution, print that there was an error." + self decreaseDepthLevel. + self record: 'End with error: ' , logMessage , '.' , (errorMessage + ifNil: [ '' ] + ifNotNil: [ ' Error message: "' , errorMessage , '"' ]). + self indentExecutionBlock ifTrue: [ self decreaseDepthLevel ] ]. self decreaseDepthLevel. self record: 'End: ' , logMessage. - self decreaseDepthLevel. + self indentExecutionBlock ifTrue: [ self decreaseDepthLevel ]. ^ result ] @@ -232,6 +235,31 @@ TinyLogger >> increaseDepthLevel [ self depth: self depth + 1 ] +{ #category : 'accessing' } +TinyLogger >> indentExecutionBlock [ + "By setting this to true, it will add an extra indentation to #execute:recordedAs: blocks. + + Setting to true: + + 2018-11-29T23:21:04.897775+01:00: Begin: Task + 2018-11-29T23:21:04.900775+01:00: Log + 2018-11-29T23:21:04.909775+01:00: End: Task + + Setting to false: + + 2018-11-29T23:21:04.897775+01:00: Begin: Task + 2018-11-29T23:21:04.900775+01:00: Log + 2018-11-29T23:21:04.909775+01:00: End: Task + " + ^ indentExecutionBlock +] + +{ #category : 'accessing' } +TinyLogger >> indentExecutionBlock: anObject [ + + indentExecutionBlock := anObject +] + { #category : 'accessing' } TinyLogger >> indentationString [ @@ -251,7 +279,8 @@ TinyLogger >> initialize [ self depth: 0. self timestampFormatBlock: self defaultTimestampFormatBlock. self loggersMap: Dictionary new. - self indentationString: String tab + self indentationString: String tab. + self indentExecutionBlock: false ] { #category : 'accessing' }