diff --git a/source/Canopy-Core-Tests/CanopyDescriptionTest.class.st b/source/Canopy-Core-Tests/CanopyDescriptionTest.class.st new file mode 100644 index 0000000..87e3b51 --- /dev/null +++ b/source/Canopy-Core-Tests/CanopyDescriptionTest.class.st @@ -0,0 +1,35 @@ +Class { + #name : 'CanopyDescriptionTest', + #superclass : 'TestCase', + #category : 'Canopy-Core-Tests', + #package : 'Canopy-Core-Tests' +} + +{ #category : 'tests' } +CanopyDescriptionTest >> testABranchAndACellCarryADescription [ + | branch cell | + branch := CanopyBranchNode new. + cell := CanopyCell new value: 1. + branch description: 'where the limits live'. + cell description: 'the maximum of open files'. + self assert: branch description equals: 'where the limits live'. + self assert: cell description equals: 'the maximum of open files' +] + +{ #category : 'tests' } +CanopyDescriptionTest >> testAHolderCarriesADescriptionAndLabels [ + | holder | + holder := CanopyValue value: 1. + holder description: 'what the component says'. + holder labelAt: #database put: 'alpha'. + self assert: holder description equals: 'what the component says'. + self assert: (holder labels at: #database) equals: 'alpha' +] + +{ #category : 'tests' } +CanopyDescriptionTest >> testNothingIsDescribedUnlessSomeoneSaidSo [ + self assert: CanopyBranchNode new description isNil. + self assert: (CanopyCell new value: 1) description isNil. + self assert: (CanopyValue value: 1) description isNil. + self assert: (CanopyValue value: 1) labels isEmpty +] diff --git a/source/Canopy-Core/CanopyNode.class.st b/source/Canopy-Core/CanopyNode.class.st index b3a9e22..eff130e 100644 --- a/source/Canopy-Core/CanopyNode.class.st +++ b/source/Canopy-Core/CanopyNode.class.st @@ -4,7 +4,8 @@ Class { #instVars : [ 'parent', 'tags', - 'labels' + 'labels', + 'description' ], #category : 'Canopy-Core', #package : 'Canopy-Core' @@ -28,6 +29,19 @@ CanopyNode >> allKeys [ ifNil: [ #() ] ] +{ #category : 'accessing' } +CanopyNode >> description [ + "What this node is for, declared where the tree is built. Branches, cells and accessors all + carry one. Nil when nobody said; the export then falls back to what the value holder of a + leaf brings along, and last to the key." + ^ description +] + +{ #category : 'accessing' } +CanopyNode >> description: aString [ + description := aString +] + { #category : 'accessing' } CanopyNode >> fullKey [ ^ '_' join: (self allKeys collect: [ :k | k asString ]) diff --git a/source/Canopy-Core/CanopyValueHolder.class.st b/source/Canopy-Core/CanopyValueHolder.class.st index 420eab0..da86a2a 100644 --- a/source/Canopy-Core/CanopyValueHolder.class.st +++ b/source/Canopy-Core/CanopyValueHolder.class.st @@ -2,7 +2,9 @@ Class { #name : 'CanopyValueHolder', #superclass : 'Object', #instVars : [ - 'value' + 'value', + 'description', + 'labels' ], #category : 'Canopy-Core', #package : 'Canopy-Core' @@ -22,6 +24,36 @@ CanopyValueHolder >> asCanopyValue [ ^ self ] +{ #category : 'accessing' } +CanopyValueHolder >> description [ + "What the component itself says this value is for. A description on the node wins over + this one - see CanopyNode>>description - so this is the fallback a component brings along." + ^ description +] + +{ #category : 'accessing' } +CanopyValueHolder >> description: aString [ + description := aString +] + +{ #category : 'initialization' } +CanopyValueHolder >> initialize [ + super initialize. + labels := Dictionary new +] + +{ #category : 'accessing' } +CanopyValueHolder >> labelAt: aKey put: anObject [ + "A label the component itself knows, as opposed to one the tree carries - the stage of a + deployment hangs at the root, the database a number belongs to is known here." + labels at: aKey put: anObject +] + +{ #category : 'accessing' } +CanopyValueHolder >> labels [ + ^ labels +] + { #category : 'printing' } CanopyValueHolder >> printOn: aStream [ super printOn: aStream. diff --git a/source/Canopy-Metrics-Tests/CanopyDeclaredMetricTest.class.st b/source/Canopy-Metrics-Tests/CanopyDeclaredMetricTest.class.st index 1e3cfe3..40dbd24 100644 --- a/source/Canopy-Metrics-Tests/CanopyDeclaredMetricTest.class.st +++ b/source/Canopy-Metrics-Tests/CanopyDeclaredMetricTest.class.st @@ -25,6 +25,20 @@ CanopyDeclaredMetricTest >> setUp [ branch := root /+ #server ] +{ #category : 'tests' } +CanopyDeclaredMetricTest >> testTheNodeDescriptionBeatsTheOneOfTheHolder [ + "The node is the declaration made where the tree is built, the holder only what the component + brings along when it is read - so the node wins, and the holder answers only where the node + says nothing." + | described | + branch counter: #requests description: 'from the holder' reading: [ 3 ]. + branch counter: #errors description: 'from the holder' reading: [ 1 ]. + described := branch / #requests. + described description: 'from the node'. + self assert: (self scrape includesSubstring: '# HELP server_requests from the node'). + self assert: (self scrape includesSubstring: '# HELP server_errors from the holder') +] + { #category : 'tests' } CanopyDeclaredMetricTest >> testACounterIsWrittenAsOne [ branch counter: #requests description: 'requests served' reading: [ 3 ]. diff --git a/source/Canopy-Metrics/CanopyMetric.class.st b/source/Canopy-Metrics/CanopyMetric.class.st index c15e6dc..dc5de97 100644 --- a/source/Canopy-Metrics/CanopyMetric.class.st +++ b/source/Canopy-Metrics/CanopyMetric.class.st @@ -2,42 +2,12 @@ Class { #name : 'CanopyMetric', #superclass : 'CanopyValueHolder', #instVars : [ - 'type', - 'description', - 'labels' + 'type' ], #category : 'Canopy-Metrics', #package : 'Canopy-Metrics' } -{ #category : 'accessing' } -CanopyMetric >> description [ - ^ description -] - -{ #category : 'accessing' } -CanopyMetric >> description: aString [ - description := aString -] - -{ #category : 'initialization' } -CanopyMetric >> initialize [ - super initialize. - labels := Dictionary new -] - -{ #category : 'accessing' } -CanopyMetric >> labelAt: aKey put: anObject [ - "A label the component itself knows, as opposed to one the tree carries - the stage of a - deployment hangs at the root, the database a number belongs to is known here." - labels at: aKey put: anObject -] - -{ #category : 'accessing' } -CanopyMetric >> labels [ - ^ labels -] - { #category : 'enumerating' } CanopyMetric >> readingsDo: aBlock [ "One reading: the labels this metric knows itself, and its value. Whatever the tree adds is diff --git a/source/Canopy-Metrics/CanopyPrometheusVisitor.class.st b/source/Canopy-Metrics/CanopyPrometheusVisitor.class.st index 2dfc3d4..d19981d 100644 --- a/source/Canopy-Metrics/CanopyPrometheusVisitor.class.st +++ b/source/Canopy-Metrics/CanopyPrometheusVisitor.class.st @@ -112,7 +112,8 @@ CanopyPrometheusVisitor >> writeHelpLine: aNode holder: aMetric [ nextPutAll: '# HELP '; nextPutAll: (self convertMetricName: aNode); nextPutAll: ' '. - stream nextPutAll: (aMetric description ifNil: [ aNode key asString ]). + stream nextPutAll: (aNode description + ifNil: [ aMetric description ifNil: [ aNode key asString ] ]). stream nextPut: Character linefeed ]