From c20d3b863bb028ecdd61aa081276c525380cf8f1 Mon Sep 17 00:00:00 2001 From: Christophe Touze Date: Tue, 18 May 2021 05:14:16 -0700 Subject: [PATCH 1/3] StatstD with tags --- source/StatsDClient/StatsDClientBase.class.st | 173 ++++++++++++++++++ .../StatsDClientBaseTest.class.st | 77 +++++++- 2 files changed, 248 insertions(+), 2 deletions(-) diff --git a/source/StatsDClient/StatsDClientBase.class.st b/source/StatsDClient/StatsDClientBase.class.st index b13443b..1babb87 100644 --- a/source/StatsDClient/StatsDClientBase.class.st +++ b/source/StatsDClient/StatsDClientBase.class.st @@ -37,6 +37,42 @@ StatsDClientBase >> format: aName value: aValue rate: aRate type: aType [ ]] ] +{ #category : #Tags } +StatsDClientBase >> format: aName value: aValue rate: aRate type: aType withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + | keys | + ^ String + streamContents: [ :str | + str + nextPutAll: prefix; + nextPutAll: aName; + nextPut: $:; + nextPutAll: aValue; + nextPut: $|; + nextPutAll: aType. + aRate < 1 + ifTrue: [ "Formating a float is expensive. So maybe have a look for standard values" + str + nextPut: $|; + nextPut: $@; + nextPutAll: aRate asString ]. + aDictionary isEmpty + ifFalse: [ str + nextPut: $|; + nextPut: $# ]. + 1 to: (keys := aDictionary keys) size do: [ :i | + | key | + i = 1 + ifFalse: [ str nextPut: $, ]. + key := keys at: i. + str nextPutAll: key. + str nextPut: $:. + str nextPutAll: (aDictionary at: key) asString ] ] +] + { #category : #format } StatsDClientBase >> formatCounter: aCounterName value: aValue [ ^self formatCounter: aCounterName value: aValue rate: 1 @@ -47,6 +83,33 @@ StatsDClientBase >> formatCounter: aCounterName value: aValue rate: aRate [ ^self format: aCounterName value: aValue asString rate: aRate type: 'c' ] +{ #category : #Tags } +StatsDClientBase >> formatCounter: aCounterName value: aValue rate: aRate withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + format: aCounterName + value: aValue asString + rate: aRate + type: 'c' + withTags: aDictionary +] + +{ #category : #Tags } +StatsDClientBase >> formatCounter: aCounterName value: aValue withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + formatCounter: aCounterName + value: aValue + rate: 1 + withTags: aDictionary +] + { #category : #format } StatsDClientBase >> formatGauge: aGaugeName value: aValue [ ^self formatGauge: aGaugeName value: aValue rate: 1 @@ -57,6 +120,33 @@ StatsDClientBase >> formatGauge: aGaugeName value: aValue rate: aRate [ ^self format: aGaugeName value: aValue asString rate: aRate type: 'g' ] +{ #category : #Tags } +StatsDClientBase >> formatGauge: aGaugeName value: aValue rate: aRate withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + format: aGaugeName + value: aValue asString + rate: aRate + type: 'g' + withTags: aDictionary +] + +{ #category : #Tags } +StatsDClientBase >> formatGauge: aGaugeName value: aValue withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + formatGauge: aGaugeName + value: aValue + rate: 1 + withTags: aDictionary +] + { #category : #format } StatsDClientBase >> formatSet: aSetName value: aValue [ ^self formatSet: aSetName value: aValue rate: 1 @@ -67,6 +157,33 @@ StatsDClientBase >> formatSet: aSetName value: aValue rate: aRate [ ^self format: aSetName value: aValue asString rate: aRate type: 's' ] +{ #category : #Tags } +StatsDClientBase >> formatSet: aSetName value: aValue rate: aRate withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + format: aSetName + value: aValue asString + rate: aRate + type: 's' + withTags: aDictionary +] + +{ #category : #Tags } +StatsDClientBase >> formatSet: aSetName value: aValue withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + formatSet: aSetName + value: aValue + rate: 1 + withTags: aDictionary +] + { #category : #format } StatsDClientBase >> formatTimer: aTimerName value: aValue [ ^self formatTimer: aTimerName value: aValue rate: 1 @@ -77,6 +194,33 @@ StatsDClientBase >> formatTimer: aTimerName value: aValue rate: aRate [ ^self format: aTimerName value: aValue asString rate: aRate type: 'ms' ] +{ #category : #Tags } +StatsDClientBase >> formatTimer: aTimerName value: aValue rate: aRate withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + format: aTimerName + value: aValue asString + rate: aRate + type: 'ms' + withTags: aDictionary +] + +{ #category : #Tags } +StatsDClientBase >> formatTimer: aTimerName value: aValue withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + formatTimer: aTimerName + value: aValue + rate: 1 + withTags: aDictionary +] + { #category : #'as yet unclassified' } StatsDClientBase >> forwardEvent: aRate [ ^aRate < 1 @@ -98,11 +242,40 @@ StatsDClientBase >> increment: aName by: aCount rate: aRate [ self sendData: (self formatCounter: aName value: aCount rate: aRate)] ] +{ #category : #api } +StatsDClientBase >> increment: aName by: aCount rate: aRate withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + (self forwardEvent: aRate) + ifTrue: [ self + sendData: + (self + formatCounter: aName + value: aCount + rate: aRate + withTags: aDictionary) ] +] + { #category : #api } StatsDClientBase >> increment: aName rate: aRate [ ^self increment: aName by: 1 rate: aRate. ] +{ #category : #api } +StatsDClientBase >> increment: aName rate: aRate withTags: aDictionary [ + "Adding tags to the statistics generation + Argument added : aDictionary. + Tags are expressed under a key-value form" + + ^ self + increment: aName + by: 1 + rate: aRate + withTags: aDictionary +] + { #category : #'as yet unclassified' } StatsDClientBase >> initialize [ super initialize. diff --git a/source/StatsDClient/StatsDClientBaseTest.class.st b/source/StatsDClient/StatsDClientBaseTest.class.st index 594887d..9857736 100644 --- a/source/StatsDClient/StatsDClientBaseTest.class.st +++ b/source/StatsDClient/StatsDClientBaseTest.class.st @@ -10,12 +10,12 @@ Class { #category : #'StatsDClient-Tests' } -{ #category : #'as yet unclassified' } +{ #category : #'set up' } StatsDClientBaseTest >> setUp [ client := StatsDClientBase new. ] -{ #category : #'as yet unclassified' } +{ #category : #tests } StatsDClientBaseTest >> testFormat [ self assert: (client formatCounter: 'counter' value: 1) equals: 'counter:1|c'. @@ -31,3 +31,76 @@ StatsDClientBaseTest >> testFormat [ self assert: (client formatTimer: 'timer' value: 1 rate: 0.9) equals: 'timer:1|ms@0.9'. ] + +{ #category : #'test Tags' } +StatsDClientBaseTest >> testFormatWithTags [ + "Adding tags to the statistics generation" + + | dico | + dico := Dictionary new. + dico at: 'key1' put: 1. + dico at: 'key2' put: 2.5. + dico at: 'key3' put: 'string3'. + + "counter" + self + assert: + (client + formatCounter: 'counter' + value: 1 + rate: 1 + withTags: dico) + equals: 'counter:1|c|#key1:1,key2:2.5,key3:string3'. + self + assert: + (client + formatCounter: 'counter' + value: 1 + rate: 0.9 + withTags: dico) + equals: 'counter:1|c|@0.9|#key1:1,key2:2.5,key3:string3'. + + "gauge" + dico := Dictionary new. + dico at: 'key5' put: 4.3. + self + assert: + (client + formatGauge: 'gauge' + value: 99 + rate: 1 + withTags: dico) + equals: 'gauge:99|g|#key5:4.3'. + self + assert: + (client + formatGauge: 'gauge' + value: '+1' + rate: 0.9 + withTags: dico) + equals: 'gauge:+1|g|@0.9|#key5:4.3'. + + "set" + self assert: (client formatSet: 'set' value: 1 withTags: dico) equals: 'set:1|s|#key5:4.3'. + self + assert: + (client + formatSet: 'set' + value: 1 + rate: 0.9 + withTags: dico) + equals: 'set:1|s|@0.9|#key5:4.3'. + + "timer" + dico := Dictionary new. + dico at: 'key6' put: 'string2'. + self assert: (client formatTimer: 'timer' value: 1 withTags: dico) equals: 'timer:1|ms|#key6:string2'. + self + assert: + (client + formatTimer: 'timer' + value: 1 + rate: 0.9 + withTags: dico) + equals: 'timer:1|ms|@0.9|#key6:string2' +] From dea23d7b09844d4e49a4d27f00cd3ca6cf0a1d53 Mon Sep 17 00:00:00 2001 From: Christophe Touze Date: Tue, 18 May 2021 05:51:19 -0700 Subject: [PATCH 2/3] bug fixed in case a rate is given : a | was missing --- source/StatsDClient/StatsDClientBase.class.st | 2 ++ source/StatsDClient/StatsDClientBaseTest.class.st | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/source/StatsDClient/StatsDClientBase.class.st b/source/StatsDClient/StatsDClientBase.class.st index 1babb87..de39ca9 100644 --- a/source/StatsDClient/StatsDClientBase.class.st +++ b/source/StatsDClient/StatsDClientBase.class.st @@ -31,7 +31,9 @@ StatsDClientBase >> format: aName value: aValue rate: aRate type: aType [ nextPutAll: aType. aRate < 1 ifTrue: [ "Formating a float is expensive. So maybe have a look for standard values" + "chrisT : | was missing in this case" str + nextPut: $|; nextPut: $@; nextPutAll: aRate asString. ]] diff --git a/source/StatsDClient/StatsDClientBaseTest.class.st b/source/StatsDClient/StatsDClientBaseTest.class.st index 9857736..d518a12 100644 --- a/source/StatsDClient/StatsDClientBaseTest.class.st +++ b/source/StatsDClient/StatsDClientBaseTest.class.st @@ -19,16 +19,16 @@ StatsDClientBaseTest >> setUp [ StatsDClientBaseTest >> testFormat [ self assert: (client formatCounter: 'counter' value: 1) equals: 'counter:1|c'. - self assert: (client formatCounter: 'counter' value: 1 rate: 0.9) equals: 'counter:1|c@0.9'. + self assert: (client formatCounter: 'counter' value: 1 rate: 0.9) equals: 'counter:1|c|@0.9'. self assert: (client formatGauge: 'gauge' value: 99) equals: 'gauge:99|g'. - self assert: (client formatGauge: 'gauge' value: '+1' rate: 0.9) equals: 'gauge:+1|g@0.9'. + self assert: (client formatGauge: 'gauge' value: '+1' rate: 0.9) equals: 'gauge:+1|g|@0.9'. self assert: (client formatSet: 'set' value: 1) equals: 'set:1|s'. - self assert: (client formatSet: 'set' value: 1 rate: 0.9) equals: 'set:1|s@0.9'. + self assert: (client formatSet: 'set' value: 1 rate: 0.9) equals: 'set:1|s|@0.9'. self assert: (client formatTimer: 'timer' value: 1) equals: 'timer:1|ms'. - self assert: (client formatTimer: 'timer' value: 1 rate: 0.9) equals: 'timer:1|ms@0.9'. + self assert: (client formatTimer: 'timer' value: 1 rate: 0.9) equals: 'timer:1|ms|@0.9'. ] From 02776b66c5064867560b9e26a0f3b7abea26c339 Mon Sep 17 00:00:00 2001 From: Christophe Touze Date: Thu, 20 May 2021 13:49:38 -0700 Subject: [PATCH 3/3] - use of #increment:rate:withTags: in #handleToInternal:from:to: and #handleToExternal:from:to: methods of RHCentral when we have a 'customer profile name' and a 'sponsor name - instance variable added : "atomicContent" on the NullStatsDClient class to buffer the messages - modifications of the methods like #increment... in the NullStatsDClient class to be able to log messages --- source/StatsDClient/NullStatsDClient.class.st | 58 +++++++++++++++++-- source/StatsDClient/StatsDClientBase.class.st | 4 +- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/source/StatsDClient/NullStatsDClient.class.st b/source/StatsDClient/NullStatsDClient.class.st index 49ca877..b75155a 100644 --- a/source/StatsDClient/NullStatsDClient.class.st +++ b/source/StatsDClient/NullStatsDClient.class.st @@ -1,26 +1,76 @@ " -I do no work +I do no work. + +""2021/05/20"" +The instance variable atomicContent has bee added in order to use Unittests (and to test contents of data send to a NulStatsDClient object) outside of StatsDClientTest scope + + " Class { #name : #NullStatsDClient, #superclass : #StatsDClientBase, + #instVars : [ + 'atomicContent' + ], #category : #StatsDClient } +{ #category : #'accessing-initialize' } +NullStatsDClient >> atomicContent [ + ^ atomicContent +] + { #category : #'as yet unclassified' } NullStatsDClient >> decrement: aName rate: aRate [ ] +{ #category : #Tags } +NullStatsDClient >> format: aName value: aValue rate: aRate type: aType [ + "We store the string in the temporary buffer atomicContent" + + atomicContent := super + format: aName + value: aValue + rate: aRate + type: aType. + ^ atomicContent +] + +{ #category : #Tags } +NullStatsDClient >> format: aName value: aValue rate: aRate type: aType withTags: aDictionary [ + "We store the string in the temporary buffer atomicContent" + + atomicContent := super + format: aName + value: aValue + rate: aRate + type: aType + withTags: aDictionary. + ^ atomicContent +] + { #category : #'as yet unclassified' } NullStatsDClient >> gauge: aName value: aValue rate: aRate [ ] -{ #category : #'as yet unclassified' } +{ #category : #api } NullStatsDClient >> increment: aName by: aCount rate: aRate [ + ^ self formatCounter: aName value: aCount rate: aRate ] -{ #category : #'as yet unclassified' } -NullStatsDClient >> increment: aName rate: aRate [ +{ #category : #Tags } +NullStatsDClient >> increment: aName by: aCount rate: aRate withTags: aDictionary [ + ^ self + formatCounter: aName + value: aCount + rate: aRate + withTags: aDictionary +] + +{ #category : #'accessing-initialize' } +NullStatsDClient >> initialize [ + super initialize. + atomicContent := String new ] { #category : #'as yet unclassified' } diff --git a/source/StatsDClient/StatsDClientBase.class.st b/source/StatsDClient/StatsDClientBase.class.st index de39ca9..0b1d86b 100644 --- a/source/StatsDClient/StatsDClientBase.class.st +++ b/source/StatsDClient/StatsDClientBase.class.st @@ -244,7 +244,7 @@ StatsDClientBase >> increment: aName by: aCount rate: aRate [ self sendData: (self formatCounter: aName value: aCount rate: aRate)] ] -{ #category : #api } +{ #category : #Tags } StatsDClientBase >> increment: aName by: aCount rate: aRate withTags: aDictionary [ "Adding tags to the statistics generation Argument added : aDictionary. @@ -265,7 +265,7 @@ StatsDClientBase >> increment: aName rate: aRate [ ^self increment: aName by: 1 rate: aRate. ] -{ #category : #api } +{ #category : #Tags } StatsDClientBase >> increment: aName rate: aRate withTags: aDictionary [ "Adding tags to the statistics generation Argument added : aDictionary.