Step 22 C: metrics over the registry, documentation, PR-doc

The metrics page sums the registered repositories' sizes; the instance
configuration is documented in docs/configuration.md, the architecture skill,
AGENTS.md and the step 22 plan (session C ticked, fairness decided FIFO).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-09-02 09:06:13 +02:00
co-authored by Claude Fable 5.1
parent b66d26a03a
commit 58799ed0ed
8 changed files with 199 additions and 13 deletions
@@ -1,6 +1,7 @@
package de.hoennig.werkator.metrics
import de.hoennig.werkator.build.ArtifactStore
import de.hoennig.werkator.repo.RepoRegistry
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.time.Clock
@@ -16,10 +17,12 @@ class MetricsConfiguration {
@Bean
fun systemMetricsCollector(
artifactStore: ArtifactStore,
registry: RepoRegistry,
clock: Clock,
): SystemMetricsCollector =
SystemMetricsCollector(
stateFile = { artifactStore.rootDir().resolve(SystemMetricsCollector.STATE_FILE_NAME) },
repoDirs = { registry.all().map { it.workingDir } },
clock = clock,
)
}
@@ -35,7 +35,8 @@ data class PersistedMetricsState(
*/
class SystemMetricsCollector(
private val stateFile: () -> Path,
private val workingDir: Path = Paths.get("."),
/** The served repositories: the disk metric is the first one's file store, the repository size their sum. */
private val repoDirs: () -> List<Path> = { listOf(Paths.get(".")) },
private val clock: Clock = Clock.systemUTC(),
private val procStat: Path = Paths.get("/proc/stat"),
private val procMeminfo: Path = Paths.get("/proc/meminfo"),
@@ -239,7 +240,7 @@ class SystemMetricsCollector(
.removeSuffix(" kB")
.toLong()
private fun readDisk(): DiskSpace? = readSource("disk") { diskSpace(workingDir) }
private fun readDisk(): DiskSpace? = readSource("disk") { diskSpace(repoDirs().first()) }
/**
* The repository size is expensive to determine (a full file walk), so unlike
@@ -251,7 +252,7 @@ class SystemMetricsCollector(
samplesSinceRepoSizeProbe++
return lastRepoSizeGib
}
lastRepoSizeGib = readSource("repo size") { repoSizeBytes(workingDir) / BYTES_PER_GIB }
lastRepoSizeGib = readSource("repo size") { repoDirs().sumOf(repoSizeBytes) / BYTES_PER_GIB }
samplesSinceRepoSizeProbe = 1
return lastRepoSizeGib
}