From 119fe910c38c219827664105ac259625e6261b37 Mon Sep 17 00:00:00 2001 From: Norbert Hartl Date: Fri, 18 Sep 2026 09:36:54 +0200 Subject: [PATCH 1/2] Let pharo be a domain of its own MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What Pharo says about itself - the image half and the virtual machine half - used to be two domains at the root, and the deployed name pharo_image_… came out of a prefix the endpoint had been configured with. That configuration was a second description of the same tree, kept next to it, free to disagree with it. Now both hang under the domain #pharo. A series is named after the path to its node, so the deployed names fall out of the structure and an unconfigured handler writes them by itself. Co-Authored-By: Claude Opus 5 (1M context) --- source/Canopy-Core/Canopy.class.st | 9 +++++++-- .../CanopyMetricsHandlerTest.class.st | 15 +++++++++++++++ .../CanopyMetricsVisitorTest.class.st | 14 ++++++++------ .../ExternalSemaphoreTable.extension.st | 2 +- source/Canopy-Metrics/File.extension.st | 2 +- source/Canopy-Metrics/Process.extension.st | 2 +- source/Canopy-Metrics/SmalltalkImage.extension.st | 2 +- source/Canopy-Metrics/VirtualMachine.extension.st | 2 +- 8 files changed, 35 insertions(+), 13 deletions(-) diff --git a/source/Canopy-Core/Canopy.class.st b/source/Canopy-Core/Canopy.class.st index 74eee5e..96755cc 100644 --- a/source/Canopy-Core/Canopy.class.st +++ b/source/Canopy-Core/Canopy.class.st @@ -41,6 +41,7 @@ Canopy class >> registerDomainNamed: aSymbol with: aNode [ { #category : 'domains' } Canopy class >> registerImageMetrics [ + "Lands under the #pharo domain, see registerSystemMetrics." SmalltalkImage canopyRegister. Process canopyRegister. File canopyRegister @@ -48,14 +49,18 @@ Canopy class >> registerImageMetrics [ { #category : 'domains' } Canopy class >> registerSystemMetrics [ - "Convenience wrapper - registers both system-metrics domains. Not wired to any - automatic image-startup hook - a caller decides when (or whether) to invoke this." + "Everything Pharo says about itself, under the domain #pharo. That is where the exported + names pharo_image_... and pharo_virtualMachine_... come from: a metric is named after where + it hangs, so the tree says it once instead of the endpoint renaming it a second time. + Not wired to any automatic image-startup hook - a caller decides when (or whether) to + invoke this." self registerImageMetrics. self registerVirtualMachineMetrics ] { #category : 'domains' } Canopy class >> registerVirtualMachineMetrics [ + "Lands under the #pharo domain, see registerSystemMetrics." VirtualMachine canopyRegister. ^ ExternalSemaphoreTable canopyRegister ] diff --git a/source/Canopy-Metrics-Tests/CanopyMetricsHandlerTest.class.st b/source/Canopy-Metrics-Tests/CanopyMetricsHandlerTest.class.st index e251459..3372443 100644 --- a/source/Canopy-Metrics-Tests/CanopyMetricsHandlerTest.class.st +++ b/source/Canopy-Metrics-Tests/CanopyMetricsHandlerTest.class.st @@ -85,3 +85,18 @@ CanopyMetricsHandlerTest >> testHandleRequestWithConfigOnlyExportsConfiguredDoma self deny: (body includesSubstring: 'beta') ] ensure: [ Canopy reset ] ] + +{ #category : 'tests' } +CanopyMetricsHandlerTest >> testRegisteredSystemMetricsAreExportedUnderTheirPharoNames [ + "What Pharo says about itself is one domain, #pharo, and a series is named after the path to + its node - so pharo_virtualMachine_memorySize comes out of an unconfigured handler, with + nothing prepended anywhere. Before, the two halves were domains of their own and the name + only became the deployed one because the endpoint had been told to prefix them." + | body | + [ Canopy registerSystemMetrics. + self assertCollection: Canopy domainNames asArray hasSameElements: #( #pharo ). + body := (CanopyMetricsHandler new handleRequest: nil) entity contents. + self assert: (body includesSubstring: 'pharo_virtualMachine_memorySize'). + self assert: (body includesSubstring: 'pharo_image_') + ] ensure: [ Canopy reset ] +] diff --git a/source/Canopy-Metrics-Tests/CanopyMetricsVisitorTest.class.st b/source/Canopy-Metrics-Tests/CanopyMetricsVisitorTest.class.st index 2704a1e..f3672dd 100644 --- a/source/Canopy-Metrics-Tests/CanopyMetricsVisitorTest.class.st +++ b/source/Canopy-Metrics-Tests/CanopyMetricsVisitorTest.class.st @@ -34,8 +34,8 @@ CanopyMetricsVisitorTest >> testExternalObjectMetricsHaveDistinctDescriptions [ | metrics tableSize objects | [ ExternalSemaphoreTable canopyRegister. metrics := Canopy instance. - tableSize := (metrics / #virtualMachine / #externalObjectTableSize) valueHolder. - objects := (metrics / #virtualMachine / #externalObjects) valueHolder. + tableSize := (metrics / #pharo / #virtualMachine / #externalObjectTableSize) valueHolder. + objects := (metrics / #pharo / #virtualMachine / #externalObjects) valueHolder. self deny: tableSize description equals: objects description ] ensure: [ Canopy reset ] ] @@ -44,11 +44,13 @@ CanopyMetricsVisitorTest >> testExternalObjectMetricsHaveDistinctDescriptions [ CanopyMetricsVisitorTest >> testExternalObjectMetricsLiveUnderTheVirtualMachine [ "Parity with what the servers export today: pharo-metrics declares both under #virtualMachine (ExternalSemaphoreTable's pragmas say so), and external semaphores are a VM concept. Canopy - registered them under #image, which renamed two series without saying a word." + registered them under #image, which renamed two series without saying a word. Both halves of + what Pharo says about itself sit under the domain #pharo, which is where the exported name + pharo_virtualMachine_externalObjects comes from." [ ExternalSemaphoreTable canopyRegister. - self assert: (Canopy instance / #virtualMachine / #externalObjects) notNil. - self assert: (Canopy instance / #virtualMachine / #externalObjectTableSize) notNil. - self should: [ Canopy instance / #image ] raise: NotFound ] + self assert: (Canopy instance / #pharo / #virtualMachine / #externalObjects) notNil. + self assert: (Canopy instance / #pharo / #virtualMachine / #externalObjectTableSize) notNil. + self should: [ Canopy instance / #pharo / #image ] raise: NotFound ] ensure: [ Canopy reset ] ] diff --git a/source/Canopy-Metrics/ExternalSemaphoreTable.extension.st b/source/Canopy-Metrics/ExternalSemaphoreTable.extension.st index 6a48574..b2c4172 100644 --- a/source/Canopy-Metrics/ExternalSemaphoreTable.extension.st +++ b/source/Canopy-Metrics/ExternalSemaphoreTable.extension.st @@ -4,7 +4,7 @@ Extension { #name : 'ExternalSemaphoreTable' } ExternalSemaphoreTable class >> canopyRegister [ "External semaphores are a virtual machine concept, and pharo-metrics exports them under #virtualMachine. Registering them under #image renamed two series without saying so." - ^ (Canopy /+ #virtualMachine) merge: (CanopyMappingBuilder new object: self; map: CanopyBranchNode new; build) + ^ (Canopy /+ #pharo /+ #virtualMachine) merge: (CanopyMappingBuilder new object: self; map: CanopyBranchNode new; build) ] { #category : '*Canopy-Metrics' } diff --git a/source/Canopy-Metrics/File.extension.st b/source/Canopy-Metrics/File.extension.st index d80fe80..02f8197 100644 --- a/source/Canopy-Metrics/File.extension.st +++ b/source/Canopy-Metrics/File.extension.st @@ -2,7 +2,7 @@ Extension { #name : 'File' } { #category : '*Canopy-Metrics' } File class >> canopyRegister [ - ^ (Canopy /+ #image) merge: (CanopyMappingBuilder new object: self; map: CanopyBranchNode new; build) + ^ (Canopy /+ #pharo /+ #image) merge: (CanopyMappingBuilder new object: self; map: CanopyBranchNode new; build) ] { #category : '*Canopy-Metrics' } diff --git a/source/Canopy-Metrics/Process.extension.st b/source/Canopy-Metrics/Process.extension.st index ca3e0c1..0272283 100644 --- a/source/Canopy-Metrics/Process.extension.st +++ b/source/Canopy-Metrics/Process.extension.st @@ -11,7 +11,7 @@ Process class >> activeProcessListCanopy [ { #category : '*Canopy-Metrics' } Process class >> canopyRegister [ - ^ (Canopy /+ #image) merge: (CanopyMappingBuilder new object: self; map: CanopyBranchNode new; build) + ^ (Canopy /+ #pharo /+ #image) merge: (CanopyMappingBuilder new object: self; map: CanopyBranchNode new; build) ] { #category : '*Canopy-Metrics' } diff --git a/source/Canopy-Metrics/SmalltalkImage.extension.st b/source/Canopy-Metrics/SmalltalkImage.extension.st index 651620e..8f0f042 100644 --- a/source/Canopy-Metrics/SmalltalkImage.extension.st +++ b/source/Canopy-Metrics/SmalltalkImage.extension.st @@ -2,5 +2,5 @@ Extension { #name : 'SmalltalkImage' } { #category : '*Canopy-Metrics' } SmalltalkImage class >> canopyRegister [ - ^ (Canopy /+ #image) merge: (CanopyMappingBuilder new object: Smalltalk; map: CanopyBranchNode new; build) + ^ (Canopy /+ #pharo /+ #image) merge: (CanopyMappingBuilder new object: Smalltalk; map: CanopyBranchNode new; build) ] diff --git a/source/Canopy-Metrics/VirtualMachine.extension.st b/source/Canopy-Metrics/VirtualMachine.extension.st index 6dcb2b3..93bffa9 100644 --- a/source/Canopy-Metrics/VirtualMachine.extension.st +++ b/source/Canopy-Metrics/VirtualMachine.extension.st @@ -2,7 +2,7 @@ Extension { #name : 'VirtualMachine' } { #category : '*Canopy-Metrics' } VirtualMachine class >> canopyRegister [ - ^ Canopy registerDomainNamed: #virtualMachine with: (CanopyMappingBuilder new object: Smalltalk vm; map: CanopyBranchNode new; build) + ^ (Canopy /+ #pharo /+ #virtualMachine) merge: (CanopyMappingBuilder new object: Smalltalk vm; map: CanopyBranchNode new; build) ] { #category : '*Canopy-Metrics' } From 688e34918c848042d74165a148ed27ff7897d556 Mon Sep 17 00:00:00 2001 From: Norbert Hartl Date: Fri, 18 Sep 2026 10:51:28 +0200 Subject: [PATCH 2/2] Say in the domain tests that the halves live under pharo The three tests named what registerImageMetrics and its siblings put at the root. That is one level deeper now, so they say so: the domain is #pharo, and the image and virtual machine halves are its children. Co-Authored-By: Claude Opus 5 (1M context) --- .../CanopyDomainTest.class.st | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/source/Canopy-Core-Tests/CanopyDomainTest.class.st b/source/Canopy-Core-Tests/CanopyDomainTest.class.st index d1db132..23e549f 100644 --- a/source/Canopy-Core-Tests/CanopyDomainTest.class.st +++ b/source/Canopy-Core-Tests/CanopyDomainTest.class.st @@ -120,25 +120,33 @@ CanopyDomainTest >> testRegisterDomainNamedRaisesOnCollisionAndDoesNotOverwrite ] { #category : 'as yet unclassified' } -CanopyDomainTest >> testRegisterImageMetricsRegistersOnlyImageDomain [ +CanopyDomainTest >> testRegisterImageMetricsRegistersTheImageHalfUnderPharo [ + "What Pharo says about itself is one domain, #pharo, with the image half below it - the + exported name pharo_image_... is that path and nothing else." [ Canopy registerImageMetrics. - self assert: Canopy domainNames asArray equals: #( #image ) ] + self assert: Canopy domainNames asArray equals: #( #pharo ). + self assert: (Canopy / #pharo) keys asArray equals: #( #image ) ] ensure: [ Canopy reset ] ] { #category : 'as yet unclassified' } CanopyDomainTest >> testRegisterSystemMetricsRegistersImageAndVirtualMachineDomains [ "registerSystemMetrics is an explicit opt-in, not an automatic image-startup hook (Norbert, - 2026-07-21: not everyone wants this without being asked) - a caller invokes it themselves." + 2026-07-21: not everyone wants this without being asked) - a caller invokes it themselves. + Both halves land under the single domain #pharo, which is where the deployed names come + from - see Canopy class>>registerSystemMetrics." [ Canopy registerSystemMetrics. - self assertCollection: Canopy domainNames asArray hasSameElements: #( #image #virtualMachine ) ] + self assert: Canopy domainNames asArray equals: #( #pharo ). + self assertCollection: (Canopy / #pharo) keys asArray hasSameElements: #( #image #virtualMachine ) ] ensure: [ Canopy reset ] ] { #category : 'as yet unclassified' } -CanopyDomainTest >> testRegisterVirtualMachineMetricsRegistersOnlyVirtualMachineDomain [ +CanopyDomainTest >> testRegisterVirtualMachineMetricsRegistersTheVirtualMachineHalfUnderPharo [ + "See testRegisterImageMetricsRegistersTheImageHalfUnderPharo - the same for the other half." [ Canopy registerVirtualMachineMetrics. - self assert: Canopy domainNames asArray equals: #( #virtualMachine ) ] + self assert: Canopy domainNames asArray equals: #( #pharo ). + self assert: (Canopy / #pharo) keys asArray equals: #( #virtualMachine ) ] ensure: [ Canopy reset ] ]