These 44 commits are when the Protocol Buffers files have changed:
| Commit: | e6240c8 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
Add path-centric dashboard layout and rebrand the web UI as the dashboard (#225) The dashboard gains a second, path-centric layout at /dashboard/paths -- one row per path (target URL, serving agent, source, last scrape), switchable from the top bar. A path whose agent has departed stays visible, marked "gone", reconstructed from recent scrape history. Supporting protocol/state additions: - RegisterAgentRequest gains proxy_endpoints / current_endpoint_index so the dashboard can show which endpoint an agent failed over to. - RegisterPathRequest gains target_url / path_source so the path view can show the real endpoint and whether a path is static or discovered. Both are additive and optional; agents predating them leave them unset. Dashboard bug fixes (all in the not-yet-released web UI): - Live WebSocket updates never applied in the browser: the out-of-band regions were wrapped in a container <div> the htmx ws extension cannot see through, so nothing updated without a reload. Regions are now top-level siblings, verified end-to-end in a browser. - Per-agent URLs (/dashboard/agents/{id}) were not reloadable -- a reload returned the bare detail fragment. The route now tells an htmx swap from a full navigation via the HX-Request header. - The bare root (/) returned 404; it now redirects to the base path. - The live indicator now reflects the real connection state (red "reconnecting" on drop), and the reconnect backoff is capped at ~2s. Rebrand web UI -> dashboard across the whole surface: classes (ProxyUiService -> ProxyDashboardService, ...), package (proxy.ui -> proxy.dashboard), config block (proxy.ui -> proxy.dashboard), CLI flags (--ui -> --dashboard), env vars (UI_* -> DASHBOARD_*), and the default path (/ui -> /dashboard). ConfigVals regenerated. Also fixes the hostName service-discovery label, which reported the proxy's hostname instead of the agent's (a one-time series churn on upgrade). Docs: new dashboard page (renamed to web-dashboard.md) covering both layouts and the in-flight status gauges, and the "How It Works" diagram now shows the agent initiating the gRPC connection. testing/ adds a local HA harness (two proxies + two agents + Prometheus) for exercising failover and the dashboard. Claude-Session: https://claude.ai/code/session_01TSB1RVyoc2UXsKjJAUJbZZ Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| Commit: | 15526fc | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
Add a read-only operational web UI to the proxy (#224) * Add the Ktor html-builder, WebSocket, and htmx dependencies Groundwork for the operational web UI: server-rendered HTML via the Ktor HTML DSL, htmx for interaction, WebSockets for live updates. Nothing consumes them yet. All five artifacts publish at 3.5.1, the version already pinned, so no Ktor upgrade is needed. ktor-htmx and its siblings are marked experimental upstream. Verified the fat JAR still assembles correctly, since kotlinx-html arrives as a new transitive (645 classes) and this project has previously lost META-INF service entries to ShadowJar's duplicate handling: the gRPC NameResolverProvider and LoadBalancerProvider files still carry their full entries, so the DNS resolver regression did not recur. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add the proxy.ui config block and option plumbing Declares proxy.ui { enabled, port, path, refreshIntervalSecs, recentScrapesQueueSize } with --ui / --ui_port / --ui_path CLI flags and UI_ENABLED / UI_PORT / UI_PATH env vars, resolved CLI > env > config like every other option. Nothing reads them yet. Off by default, matching the admin and metrics posture: the UI renders agent names, hostnames, target URLs and recent activity in one place, on a port with neither auth nor TLS. The port is deliberately its own rather than the admin port's. Kubernetes liveness and readiness probes target /ping and /healthcheck on 8092, so sharing would mean a UI cannot be firewalled without taking the probe endpoints with it. A test pins that the two ports differ. Unlike agent.proxy.endpoints, every key here is a scalar, so tscfg emits a hasPathOrNull guard for each and for the block itself -- there is no unguarded getList, and a config predating the UI loads unchanged. A ConfigValsTest case pins that so the guard cannot silently regress. The EnvVars drift guard did its job and is updated: 47 entries to 50, with the three new names added to both the completeness list and the contains-all list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Expose the agent and scrape data the web UI needs Three source changes, none of which alter existing behavior. remoteAddr and launchId become readable on AgentContext. Both were private and leaked only through toString(). remoteAddr is the only field that establishes which machine an agent is actually on -- agentName is self-reported -- and launchId distinguishes two runs of the same agent name. AgentContext gains a wall-clock connectTime. Every other timing field is a Monotonic TimeMark, which measures elapsed time correctly but cannot be rendered as a time of day. The marks are left alone: they are immune to clock adjustments and remain the right basis for eviction. ScrapeRequestResponse now carries the agentId that served it, and a structured EvictingQueue<ScrapeRecord> is populated alongside the existing text queue. The /debug servlet's queue holds pre-formatted strings with no agent attribution and no field boundaries, so a per-agent scrape view could only be built from it by parsing display text back apart. The two queues are populated from one site and neither depends on the other; the text format stays a stable operator surface, and the structured one is sized independently because the UI shows more history than a debug dump needs. agentId is carried on the response rather than read at the logging site because executeScrapeRequests loses the AgentContext at awaitAll(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add a ProxyEvent bus so topology changes are observable Nothing in the proxy was observable before this: every collection was a plain ConcurrentHashMap or a synchronized HashMap with no listeners, callbacks, or flows, so the only way to watch state was to poll it. The bus emits at the five points where topology actually changes -- agent connect and disconnect, path register and unregister, scrape completion. Emitting is a tryEmit on a SharedFlow configured DROP_OLDEST, which never suspends and never blocks. That is what makes it safe at these call sites: they run inside synchronized(pathMap) and on gRPC transport threads, where a slow or absent subscriber must never be able to stall a registration or a disconnect. Dropping rather than buffering is deliberate. Consumers re-read a full snapshot when woken, so a missed event costs a slightly later refresh, never a wrong render -- the bus is a wake-up signal, not a ledger. Scope is deliberately narrow: only transitions with an identifiable moment. Values that drift -- backlog depth, map sizes, eviction countdowns -- have no such moment and are left to be sampled on a timer by whoever needs them, which will be the UI service rather than this bus. AgentContextManager's eventBus parameter is defaulted so the ~15 existing test call sites keep working; a private bus with no subscribers is a no-op. Proxy passes its shared instance explicitly. Tests use onSubscription rather than sleeps or yields, so subscriber registration is ordered deterministically against the first emit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add the immutable snapshot layer the UI renders from ProxySnapshot materializes agents, paths, recent scrapes and health counters into immutable views. Nothing consumes it yet. Materializing rather than referencing live state is the point: AgentContextManager.agentContextEntries is the ConcurrentHashMap's live entry set, not a snapshot, so two passes over it can disagree. Copying once means every WebSocket session renders the same consistent picture. Deliberately avoids two accessors that look useful and are not. ProxyPathManager.toPlainText() holds the path monitor across a full sort plus a toString() per entry. totalAgentScrapeRequestBacklogSize is O(agents x backlog depth) because ConcurrentLinkedQueue.size() traverses -- it is slowest exactly when backlogs are deep, which is when a health view is most likely to be watched. Cost is two monitor acquisitions per collect regardless of session count, which is why the caller must collect once and fan out rather than collect per session. Documented as unsafe to run on a Ktor CIO thread: Kotlin's synchronized parks the carrier thread, so collecting on the event loop would couple the operator UI to scrape latency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Correct the event bus contract found false by adversarial review Three review lenses each came back BROKEN. Six findings survived judging; eleven were refuted, including the two scariest -- that tryEmit resumes subscribers inline inside synchronized(pathMap), and that a lock-ordering inversion with recentScrapes becomes reachable. Neither holds. AgentConnected claimed "an agent completed registration and is now serving". It does not. It is emitted from the gRPC transport filter, which runs before per-call auth and before registerAgent, so identity is still "Unassigned" and the peer may yet be rejected -- anything completing an HTTP/2 handshake reaches it, including a health probe or a bad-token client. The KDoc now says so. Identity assignment had no event at all, so an agent registering zero paths would have shown as "Unassigned" indefinitely: nothing would ever wake a consumer to re-read it. AgentRegistered is emitted from registerAgent where the identity actually arrives. AgentDisconnected moved from AgentContextManager to Proxy.removeAgentContext, so its happens-before edge covers the path sweep as well as the context removal. Emitted at the old site, a consumer could wake between the two calls and snapshot a path map that still listed the departed agent. removeFromPathManager emitted nothing when a consolidated path survived losing one agent. That is the one case with no later event to self-correct from, so the stale render would have stuck rather than resolving on the next wake-up. Also: ScrapeRecord.statusCode is this agent's leg of a scrape, not necessarily the merged status Prometheus saw on a consolidated path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Serve htmx from WebJars rather than vendored or CDN assets ktor-htmx ships only Kotlin attribute constants (HxSwap, HxEvents, and friends) and no JavaScript, so the htmx client library has to come from somewhere. htmx 2.x also moved WebSocket support out of core into a separate extension, so two files are needed rather than one. WebJars make both normal Gradle dependencies instead of committed source: the assets arrive inside a JAR under META-INF/resources/webjars/ and Ktor serves them from the classpath. No third-party JavaScript is committed to this repository, the versions are visible to the same dependency tooling as everything else, and the assets ship inside the fat JAR -- which matters for a product whose whole purpose is running where network access is restricted. A CDN would render a blank page in exactly that environment, and it would fail at page load rather than at deploy. htmx-ext-ws declares a compatible range on core that resolves to the same 2.0.10, so the two cannot drift apart. Verified both land in the fat JAR (htmx.min.js at 51KB, ws.js at 15KB) and that the gRPC NameResolverProvider service file survived, since that merge has regressed before. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add the operational web UI: master-detail over htmx and WebSockets ProxyUiService runs its own Ktor CIO server on its own port, off by default. Not the admin port -- that is a Jetty servlet container created inside common-utils whose only extension point is a path-to-Servlet map, so Ktor routing, the HTML DSL and WebSockets cannot attach to it. Not the scrape port either: that one is Prometheus-facing and should stay predictable. A separate port also lets the UI be firewalled without taking /ping and /healthcheck with it, which Kubernetes probes target. Everything is server-rendered. The WebSocket carries HTML fragments rather than JSON, so there is no client-side templating and no duplicated view logic. Fragments carry stable ids and hx-swap-oob, letting one frame update the agent list, the detail pane and the status bar independently. Selection lives in the URL via hx-push-url, so it survives reload and is bookmarkable. The only hand-written JavaScript reads that selection back out and tells the server, since the push loop needs to know whether this session wants a detail pane -- the one thing htmx does not model. One shared push loop, not one per session: it wakes on an event or a timer tick, collects a single snapshot, and fans the same fragments to every session. The wake channel is CONFLATED so a fleet reconnecting collapses into one collect. The timer is what keeps drifting values live -- backlogs and eviction countdowns have no moment to emit from and would otherwise sit frozen between topology changes. Two things the end-to-end test caught that unit tests structurally could not. ConcurrentHashMap rejects null values, so storing "no selection" as null threw on insert and killed every session at connect; it is a sentinel now. And Ktor's staticResources did not resolve the webjar layout, whose path embeds a version -- replaced with an explicit two-entry allowlist, which also removes any path-traversal surface. The harness test connects an agent AFTER the socket is already open, so the fragment it asserts on can only have come from the push path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add the container test and document the web UI ContainersWebUiTest exists for one reason the harness test cannot cover: the fat JAR. htmx ships as a WebJar served from the classpath, so a packaging regression that drops those resources would still render the page while leaving every interaction dead -- invisible to any test that only checks HTML. Verified it fails when the asset path is broken. Documentation records the two places this implementation deliberately departs from the proposal, rather than quietly diverging. The proposal's own section title says "on the Proxy Admin Port". That is not achievable: the admin port is a Jetty servlet container created inside common-utils whose only extension point is a path-to-servlet map, so Ktor routing and WebSockets cannot attach to it. The UI runs on its own port, which also turns out to be the better posture -- Kubernetes probes target /ping and /healthcheck on the admin port, so a shared port could not be firewalled without taking the probes with it. The proposal also specifies "no framework, no external assets". As built there is still no build toolchain and no CDN, but htmx is a framework and a third-party asset. It arrives as a WebJar rather than vendored source, so nothing third-party is committed here and versions stay visible to normal dependency tooling. New website page covering what the UI shows, why it has its own port, why it works airgapped, and its limits -- including that it is unauthenticated and must be treated as internal. Cross-referenced from Troubleshooting, which is where someone lands with the question the UI answers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Record the agent-side state the UI cannot see, and how to work around it Three things operators will ask the UI for are invisible to it for one shared reason: they are facts the agent knows and the registration RPC does not carry. Path source (static vs discovered, Feature 1), failover endpoint and rotation state (Feature 2), and Feature 3 per-agent identities. The failover case has a real operational consequence worth stating before someone hits it during an incident rather than after. In an HA pair each proxy's UI shows only its own agents, so a failover makes an agent disappear from one dashboard and reappear on the other with nothing on either screen explaining why -- at exactly the moment someone is watching. There is a partial thread to pull, and the UI already renders it: launchId is generated once per agent process, so it survives a failover, while agentId is assigned by each proxy independently and does not. An operator can correlate the same agent process across two proxies by eye. Documented as the workaround it is, not as a feature. Closing any of these properly means extending RegisterPathRequest / RegisterAgentRequest -- worth doing once for all three rather than three times, which is why it is logged as one open question rather than three. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix a push-loop amplification and other cleanup-pass findings The push loop ran at scrape rate rather than the refresh interval. Every ScrapeCompleted woke it, and Channel.CONFLATED collapses bursts but imposes no floor -- so at roughly twenty scrapes a second the loop collected a snapshot twenty times a second, taking the same path-map monitor every scrape request takes. That defeated the design: ProxySnapshot.collect goes to lengths to run off the CIO event loop so the UI cannot couple to scrape latency, and the wake path coupled them anyway. Scrape history is a drifting value, which by the event bus's own contract is the timer's job, so it no longer wakes the loop. The same KDoc also overclaimed: it said it avoided an O(agents x backlog) cost, then paid exactly that per agent via scrapeRequestBacklogSize. It now says so, and explains why the refresh-interval bound makes it acceptable. renderStatus wrapped itself in a span carrying the status id, and pushFragment wrapped it again with the same id, so every frame contained nested duplicate ids. All three regions are now self-wrapping behind an oob flag, which also removed the duplicated attribute setup between renderPage and pushFragment. agentId came off ScrapeRequestResponse. It needed seven construction sites from two different expressions and defaulted to empty, so any future branch that forgot it would silently emit an unattributed record. map and awaitAll preserve order, so a zip recovers provenance at the single site that needs it. logActivityForResponse is renamed recordScrapeOutcome, since it is now where a scrape becomes observable rather than merely logged. The UI server skipped ProxyHttpConfig.configureKtorServer, so htmx.min.js went out uncompressed and failures returned bare 500s; assets were also re-read from the JAR per request on a port with no auth. Now configured like the proxy's own HTTP service, with assets read once and marked immutable. Also: ktor-htmx, ktor-htmx-html and ktor-server-htmx were shipping in the fat JAR with nothing importing them -- added on the assumption of the typed DSL, then every attribute was hand-written. Dropped. SessionKey plus a sentinel plus three null conversions became one Session object. Five unread fields removed from the snapshot DTOs, along with a test asserting a state the path manager cannot produce. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Log the departed-agent path gap as a known limit When an agent disconnects, ProxyPathManager deletes its paths rather than leaving them empty, so a zero-agent path cannot exist. Combined with an agent-centric layout, a path that has stopped working is absent from the UI entirely -- Prometheus gets a 404 and the dashboard shows nothing named after it. That is the exact question this feature was built to answer, so it is worth recording plainly rather than leaving for an operator to discover. Distinguished from the other two gaps on purpose: path source and failover visibility need a proto change, because the agent knows facts the proxy never receives. This one does not -- recentScrapes already retains records naming the path. What is missing is a view onto state the proxy already keeps, which a path-centric layout would provide. The website page frames it as troubleshooting guidance rather than a disclaimer, since that is how someone will meet it: if Prometheus reports a target failing and the path is not on the dashboard, look for a missing agent instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Report agent failover position to the proxy UI Each proxy's UI shows only its own agents, so a failover looked like an agent vanishing from one dashboard and a stranger appearing on the other -- at exactly the moment someone is watching. RegisterAgentRequest gains proxy_endpoints and current_endpoint_index. The agent reports both at registration rather than on a heartbeat because registration is precisely when they change: a failover IS a reconnect, so the index is accurate whenever the proxy learns it. Both fields are additive and optional, so an agent predating them simply leaves them unset and the UI omits the line. The detail pane renders "via proxy-b:50051 (2 of 2)" plus a "failed over" tag whenever the index is past the first entry, which is what distinguishes an agent that failed over to this proxy from one that started here. An out-of-range index degrades to no position rather than throwing -- this is remote input and an older or misbehaving agent could send anything. The harness test drives the real path: an agent whose primary endpoint is a dead port connects to its secondary, and this proxy's UI says so. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TSB1RVyoc2UXsKjJAUJbZZ --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| Commit: | c68d605 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
Add agent-side proxy failover for high availability (#223) * Add the design for proxy HA with agent-side failover Records the Phase 1 decisions: an agent.proxy.endpoints list alongside a comma-accepting --proxy/PROXY_HOSTNAME, rotation that advances on connect failure and resets to the head of the list on a dropped-but-established connection, unchanged pacing, and an app-level cursor rather than a gRPC NameResolver. Also records the constraints that research verified against the code, several of which contradict the original proposal: a standby proxy returns 404 rather than 503 for an unregistered path, http_sd_config silently deletes a standby's targets so the HA recipe must mandate static_config, and reference.conf must default the new list or every existing config fails to load. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add the agent.proxy.endpoints config key for failover Declares an ordered endpoints list on agent.proxy and regenerates ConfigVals. Nothing reads it yet -- the rotation logic follows. The reference.conf default is load-bearing, not cosmetic. tscfg emits an unguarded c.getList("endpoints") for a list-typed key, in contrast to the hasPathOrNull check it generates for the sibling hostname/port scalars, so without agent.proxy.endpoints = [] every config written before this feature existed would fail to load with ConfigException.Missing. Two ConfigVals tests pin that, one of them shaped like an existing deployment's config; both fail if the reference.conf line is removed. That same asymmetry broke three test fixtures that built ConfigVals from a bare parseString. They now merge the reference config the way BaseOptions.readConfig does in production, which also immunizes them against the next list-typed key. ProxyServiceImplTest was among them despite being proxy-only, because ConfigVals eagerly constructs both trees. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Rotate through proxy endpoints on connect failure, fail back on drop The agent now accepts an ordered list of proxy endpoints and tries them in order. --proxy and PROXY_HOSTNAME take a comma-separated value, and agent.proxy.endpoints supplies the same list from a config file; a single value resolves to a one-element list and behaves exactly as before. Rotation is driven by one bit already present in the retry loop: agentId is non-empty at the top of an iteration only if the previous attempt actually connected. A connection that came up and then dropped resets to the head of the list, so a recovered primary is re-probed -- that is the whole failback mechanism, with no prober, timer, or per-endpoint state. An attempt that never connected advances to the next endpoint. The channel rebuild is the load-bearing part rather than an incidental one. A ManagedChannel is bound to its target address, and connectToProxy only rebuilt after a *successful* connection, so a run of failures reused one channel against one address. Without changing that guard a cursor would advance an index nothing reads. The rebuild on the advance path is conditional on the endpoint actually changing, so a single-endpoint agent keeps reusing its channel and leaning on gRPC's own backoff instead of gaining channel churn on every failed retry. Rotation never builds channels itself -- only resetGrpcStubs does -- so the shutDownRequested latch keeps winning and a rotation cannot resurrect a channel after a requested stop. A test pins that. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix IPv6 endpoint corruption and a torn host:port read found by review Adversarial review of the rotation change confirmed three defects. The rotation logic itself held up -- both the "does failover happen" and "is the single-endpoint path unchanged" lenses came back clean -- but the config resolution path did not. IPv6 endpoints were silently corrupted. parseHostPort strips the brackets off an IPv6 literal, and AgentOptions normalizes every configured endpoint by rendering the parsed HostPort back to "$host:$port" and re-parsing it. Without brackets that string re-parses as a BARE IPv6 address with no port, so the agent dialed a garbage authority on the default port and simply never connected -- no exception, no clue. HostPort.spec now re-brackets any host containing a colon, making the render the exact inverse of the parse and leaving IPv4/DNS output byte-identical. The hostname half of this round trip predates the branch; the endpoints key extended it. Agent.proxyHost composed two independent reads of the volatile cursor, one for host and one for port, so a rotation landing between them could make the /debug servlet print a host:port pair that was never configured. A single-read currentEndpoint accessor removes the window. A scheme-only entry such as "http://" passed the blank filter on its raw text and then failed with a message naming neither the entry nor the list. The gap that hid the IPv6 bug is closed too: assignConfigVals' endpoint resolution was entirely untested because every existing AgentOptionsTest case passes --proxy, which skips that block. A dedicated test config now drives it, IPv6 entry included. All five new tests fail if HostPort.spec is reverted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add a Netty harness test for proxy endpoint failover Two proxies run simultaneously on distinct gRPC ports; the agent is pointed at both, must start on the first, and must land on the second once the first stops. Netty rather than in-process is a hard requirement, not a preference: GrpcDsl ignores hostName and port entirely when an in-process server name is supplied, so an in-process failover spec would build the same channel whichever endpoint the cursor selected and would pass without any rotation occurring. Distinct ports matter for the same reason -- they make this a test of endpoint selection rather than of a name resolving to a new address, which ContainersReconnectTest already covers. The path lives in pathConfigs rather than being registered by the test, because a runtime registration does not survive a reconnect; only a config-driven path proves the agent re-registered on the endpoint it failed over TO. The assertion scrapes proxy B's own HTTP port, which can only succeed if the agent registered there, and additionally checks the cursor moved and that B issued a new agentId. Verified the test bites: with advanceEndpoint() forced to return false, it fails. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add a two-proxy container test for endpoint failover proxyContainer unconditionally claimed the shared proxy-host alias, so two instances landed behind one name and Docker's embedded DNS round-robined between them non-deterministically. It now takes an alias (mirroring agentContainer and metricsStub) plus a log label, so an HA pair is addressable and its logs are distinguishable. The new spec runs both proxies on distinct aliases and asserts the agent resumes serving through the standby's OWN alias after the active proxy stops -- which is only possible if the agent selected B's endpoint and re-registered there. Distinct aliases are what make this a failover test: ContainersReconnectTest replaces a proxy at one alias and therefore proves DNS re-resolution, so a spec copied from it would pass even with rotation unimplemented. Verified both directions against real containers: passes as written, and fails when advanceEndpoint() is forced to return false. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Document proxy failover and reconcile the contradictory HA docs Covers the feature in the README CLI table, the agent configuration page, the production HA guide, CHANGELOG, and release notes, and marks Feature 2 as implemented with as-built notes recording where it diverged from the proposal. Two pre-existing doc problems are fixed rather than worked around. Proxy.kt's KDoc already asserted that agents "automatically reconnect to available proxies" -- on a Dokka-published type -- while production.md said the opposite; this release makes the claim true, so both now describe the same mechanism and state plainly that proxies share no state. And the proposal's assertion that a standby returns 503 for an unregistered path was simply wrong: it returns 404, since a null agent context routes to invalidPathResponse. Prometheus scores both as up=0, so the conclusion held, but the code would have propagated into alert rules. The http_sd_config hazard is called out prominently in all three operator-facing places. A standby returns an empty discovery list, which Prometheus treats as target deletion rather than a failed scrape -- so the series vanish with no up=0 and no alert, defeating the point of running a pair. The HA recipe mandates static_config. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Build each container image once per JVM instead of once per container proxyImage()/agentImage() were functions used as default parameter values, so every container constructed its own ImageFromDockerfile -- and Testcontainers gives each instance its own random localhost/testcontainers/<hash>:latest tag. ContainersScalingTest builds one agent container per agent, so a single run minted a tag per agent plus one per proxy. The layers are content-hashed and shared, so this costs no build time, but the tags accumulate: they are reaped only by a JVM shutdown hook that never fires when a run is killed or times out. On this machine that had grown to 5800 tags resolving to 357 distinct images, 60.7GB with 85% reclaimable. Sharing one lazily-built instance per image is the documented way to build once and reuse: the value is a Future<String> resolved on first use. Verified against real containers -- a run with two proxy containers and one agent now creates two tags rather than three, and the failover spec still passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Report the agent's own hostname at registration, not the proxy endpoint registerAgent sent agentHostName -- the proxy endpoint the agent had dialed -- in the request's host_name field. The proxy stores that on AgentContext and publishes it as the reserved `hostName` service-discovery label, which is documented in Proxy.kt's KDoc and service-discovery.md as "hostnames of agents serving this path" and which agents are explicitly forbidden from overriding. The proxy's own tests encode that meaning: AgentContextTest stubs the request field as "agent-host", and ProxyTest asserts the emitted label is "internal.host.com". So every discovered target carried the same value -- all agents connect to the same proxy -- and a label meant to identify which internal host serves a path identified nothing. Fixed now rather than filed, because failover makes it actively harmful rather than merely useless: hostName participates in Prometheus target identity, so a value tracking the current endpoint would change on every failover and churn the series each time. That would be a regression introduced by this branch. The nearby channel(hostName = agentHostName, ...) is untouched -- there the name correctly means "the host to dial". Operator-visible, so CHANGELOG and RELEASE_NOTES carry an upgrade note: the label value changes, causing a one-time series churn. Covered by a test that captures the outbound request and fails if the proxy endpoint is sent again. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Remove the dead proxy_url field from RegisterAgentResponse The field was declared and never read or written anywhere in the codebase -- its only occurrence was the declaration itself. That makes it a trap: it reads like a server-driven redirect mechanism, which does not exist. Agent-side proxy failover is driven by the agent's own ordered endpoint list, not by anything the proxy returns. Both the number and the name are reserved so neither can be reused with different semantics later. No wire-compatibility concern: nothing ever populated the field, so no serialized message has ever carried it, and proto3 readers ignore unknown fields regardless. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Apply cleanup-pass fixes to the failover implementation and its tests Review found one real defect: currentEndpoint exists so the volatile cursor is read once, but the channel-construction site read it twice (hostName = agentHostName, port = agentPort), contradicting the invariant the accessor was added for. It is under grpcLock so it could not actually interleave there, but the shape was wrong; it now binds once. Reuse: AgentProxyFailoverTest hand-rolled proxy and agent startup because TestUtils.startProxy hardcodes the port and unconditionally adds --config, which is a single-valued JCommander parameter and so cannot be overridden through args. Both helpers gained defaulted proxyPort/configArgs parameters -- source-compatible with all nine existing callers -- and the private copies are gone. Removed over-engineering added by this branch: proxyContainer's logLabel parameter, whose only two callers passed exactly the default, and the widened PROXY_ALIAS visibility, whose only external reference was a comment. DEFAULT_GRPC_PORT moves to AgentOptions so the public options type stops importing from the internals of the gRPC client it configures. The two AgentOptions fallback branches were one expression written twice and had already drifted -- only the list branch applied stripScheme/trim. Collapsed to one, which means agent.proxy.hostname now tolerates a scheme prefix where it previously threw at startup. Tests: six rotation specs called a bare shutDown(), so a failed assertion leaked a channel into the next spec; they share a try/finally helper now. The tscfg reference-merge rationale was copy-pasted into three fixtures and is now one documented testConfigVals helper. Two redundant specs folded, harness cleanup made symmetric. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| Commit: | 5cc70c4 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
3.0.0 (#117) * Comment out logger calls in HarnessSupport for cleaner code * Refactor Agent and AgentGrpcService to improve scrape request handling and update main method parameters * Refactor ProxyHttpRoutes and ScrapeRequestWrapper to streamline scrape request handling and ensure proper resource cleanup * Update dependencies and add version configuration for Gradle * Update version configuration to improve stability checks and upgrade logging library to 7.0.14 * Update utils library version to 2.5.3 for improved functionality * Downgrade Gradle wrapper to version 9.2.0 and update logback version to 1.5.29 * Refactor ScrapeRequestResponse and ResponseResults to use data classes for immutability and update tests for copy behavior * Refactor metadata handling by consolidating constants into GrpcConstants and updating imports * Refactor AgentContextInfo to use data class for improved immutability and remove unnecessary toString method * Refactor path handling to use removePrefix and removeSurrounding for cleaner code * Refactor AgentContext and AgentContextManager to improve property assignment and encapsulation * Refactor ProxyHttpRoutes to use distinct for status codes and content types, and optimize status message construction * Refactor AgentGrpcService to use ReentrantLock for thread-safe shutdown and stub creation * Refactor AgentHttpService and related classes for improved ScrapeResults handling and encapsulation * Refactor test setup to remove lambda usage for cleaner code * Refactor null checks to use explicit null comparisons for improved readability * Refactor chunk validation to throw ChunkValidationException for mismatches and enhance error handling in ProxyServiceImpl * Fix agent registration to ensure consolidated agents are added on type mismatch in ProxyPathManager * Synchronize agent ID assignment in AgentClientInterceptor to prevent race conditions * Update log message for agent removal in ProxyPathManager for clarity * Refactor request header preparation and improve exception handling in chunk validation * Refactor backlog size management to increment on the consumer side, preventing negative counts and ensuring accurate tracking * Ensure connection context is closed on completion of response writing and result scraping * Rename suspendUntilComplete to awaitCompleted for clarity and consistency in ScrapeRequestWrapper * Reorder agent context management to ensure agent context is added after agent ID validation * Refactor agentContexts to be immutable and enhance test coverage for getAgentContextInfo * Enhance path management by introducing allPathContextInfos method and updating buildServiceDiscoveryJson for improved clarity and efficiency * Refactor AgentClientInterceptor to use next channel parameter and update tests for clarity * Refactor error handling in processScrapeResults and ensure channels are closed after processing * Refactor AgentClientInterceptor to throw an error for missing AGENT_ID key and enhance tests for header handling * Refactor AgentPathManager to use HashMap for pathContextMap and synchronize access for thread safety * Fix race conditions, resource leaks, and synchronization issues in Agent and Proxy packages * Enhance writeChunkedResponsesToProxy to clean up orphaned contexts on stream failure and add corresponding tests * Improve error handling in writeResponsesToProxy and add tests for continued processing after failures * Add unary deadline configuration and update gRPC calls to use it * Add unaryDeadlineSecs option and corresponding tests for AgentOptions * Implement cleanup of agent context in readRequestsFromProxy when transportFilterDisabled and add corresponding tests * Add null checks in tests for AgentHttpService, AgentOptions, and ConfigWrappers * Clarify hashCode contract in AgentContextTest and remove redundant check for unequal objects * Refactor agentContexts to use MutableList in AgentContextInfo to eliminate unsafe casts in path management * Refactor writeChunkedResponsesToProxy to use enum constants for chunk type handling and add tests for CHUNKONEOF_NOT_SET cases * Enhance invalidate method to drain buffered scrape requests and notify HTTP handlers immediately; add tests for proper closure of request wrappers and unblock behavior * Add parsePort function to validate port values and update parseHostPort; enhance tests for error handling * Refactor dynamic parameter handling to avoid setting global system properties; update tests to verify config application without side effects * Refactor onDoneWithClient to return a boolean for client closure; update onFinishedWithClient to close client outside mutex, ensuring non-blocking cache operations during slow I/O * Refactor client closure logic in HttpClientCache to mark in-use clients for closure and close idle clients immediately; add tests to verify behavior for in-use and idle clients * Refactor AgentConnectionContext to use close() instead of cancel() for scrapeResultsChannel, allowing buffered results to be drained; add tests to verify behavior after closure * Enhance shutdown logic in AgentGrpcService to await channel termination; add tests to verify channel state before and after shutdown * Throw StatusRuntimeException with descriptive message when AGENT_ID key is missing in headers; add tests to verify exception behavior * Add test to verify entry count matches completeness list for environment variables * Refactor activity time marking in AgentContext to reduce clock calls and improve performance * Refactor invalidate method in AgentContext to drain scrape request channel and update test to verify behavior * Improve error handling in parseHostPort for malformed IPv6 addresses; update tests to verify exception messages * Fix typo in config.conf: correct "Overide" to "Override" in TLS section * Update logging for keepAliveTimeSecs and keepAliveTimeoutSecs to clarify default values * Add warning log for missing AgentContext in readRequestsFromProxy * Improve tests for AgentContext: update assertions in invalidate method and add consistency check for markActivityTime * Improve awaitCompleted method and add tests for completion scenarios * Ensure response handler is called by requiring non-null result in AgentHttpService * Handle missing X509TrustManager in getTrustManager: return error if not found * Fix typo in ConfigVals: correct "Overide" to "Override" in Javadoc comment * Fix typo in ConfigVals: correct "Overide" to "Override" in Javadoc comment * Add bug report for Prometheus Proxy codebase review with identified issues and suggested fixes * Refactor shutdown logic to prevent deadlocks during concurrent operations * Ensure backlog size consistency in scrape request handling * Handle ClosedSendChannelException in submitScrapeRequest and add corresponding tests * Add invalidateAllAgentContexts method and enhance scrape request handling * Refactor HttpClientCacheTest to use Thread.sleep for slow client simulation and ensure proper dispatcher usage * Invalidate orphaned agent contexts when a non-consolidated agent overwrites a path * Reserve field number 5 in proxy_service.proto to prevent conflicts * Reject consolidated/non-consolidated agent mismatches in addPath method to prevent unexpected behavior * Update agent context validation in addPath method to streamline path addition logic * Rename awaitCompleted parameter from waitMillis to timeout for clarity and add tests to verify Duration handling * Add input validation for parseHostPort function to prevent blank strings * Refactor agent property assignment in ProxyPathManagerTest for improved readability * Add test for variable substitution in ProxyOptions configuration * Enhance boolean environment variable handling with strict parsing and tests * Refactor respondWith function to remove redundant status setting and add integration test for expected behavior * Improve AgentContextCleanupService shutdown behavior with CountDownLatch and add test for prompt shutdown * Refactor BaseOptions to use URI for URL conversion and improve version flag handling with tests * Remove VersionValidator from Utils and update tests to ensure getVersionDesc does not trigger exitProcess * Add mock behavior for pathManager in ProxyServiceImplTest to enhance test coverage * Add isTlsEnabled property and enhance auth header forwarding warning in ProxyHttpRoutes * Add comprehensive bug report detailing fixes and improvements across the Prometheus Proxy codebase * Improve HttpClientCacheTest to enhance concurrency handling during slow client closure * Enhance HttpClientCacheTest to improve concurrency handling during slow client closure * Bump version to 3.0.0 and update related configurations * Add Semaphore CI configuration for Prometheus Proxy * Add unit tests for Agent and Proxy classes to improve test coverage * Add unit tests for AgentGrpcService and ProxyHttpConfig to enhance test coverage * Add unit tests for submitScrapeRequest to improve error handling and response validation * Add unit tests for ChunkedContext and ScrapeRequestWrapper to improve error handling and validation * Add integration tests for ProxyHttpConfig and ProxyHttpRoutes to verify server behavior and response handling * Improve test stability by adding delays to prevent flakiness in HttpClientCacheTest * Refactor tests to use FunSpec style and improve structure for better readability * Refactor test names for clarity and consistency in Admin and Harness tests * Improve test stability in HttpClientCacheTest by adding delays and using mock clients to prevent flakiness * Add coverage configuration to build.gradle.kts and refactor version check logic * Refactor tests to use StringSpec style for improved readability and consistency * Remove Semaphore CI configuration file as it is no longer in use * Refactor AgentHttpService to improve header handling and timeout logic for clarity * Fix HttpClientCache to close idle clients on eviction and cleanup * Add failScrapeRequest method to handle validation failures and notify HTTP handler * Fix backlog counter increment logic in AgentContext to prevent drift on failed writes * Ensure password char array is zeroed after use in getKeyStore method and add tests for validation * Update cache size and age validation to accept 1 as a valid value * Refactor writeScrapeRequest method to simplify backlog size management * Refactor cleanup loop in HttpClientCache to use isActive for coroutine lifecycle management * Refactor AgentPathManager to use ConcurrentHashMap and Mutex for thread-safe path registration * Fix logging in addPath method to prevent IndexOutOfBoundsException and add test for rapid overwrites * Add warning log for disabled X.509 certificate verification in AgentOptions * Fix error logging message format in BaseOptions to improve clarity * Add test for readConfig error message to verify dollar sign interpolation * Improve readability of test code in AgentPathManagerTest * Refactor addPath method to return descriptive error messages on failure and update tests accordingly * Add delay to allow CIO engine to fully initialize in ProxyHttpRoutesTest * Refactor health check to use currentCacheSize method for improved accuracy * Refactor health check test to use currentCacheSize for non-blocking behavior * Fix metrics path formatting to ensure leading slash is present * Enhance registerPath to propagate detailed failure reasons and ensure leading slashes in metrics paths * Refactor scrape request handling to use ConcurrentLinkedQueue for accurate backlog size tracking * Refactor boolean option handling to use resolveBooleanOption for improved clarity and consistency * Refactor TLS configuration handling to require both certificate and key for enabling TLS, and add validation for incomplete configurations * Fail orphaned scrape requests when cleaning up ChunkedContext on stream failure * Add tests to validate scrapeRequestBacklogSize behavior and prevent negative values * Add tests to ensure grpcStarted is correctly managed during channel initialization and shutdown * Ensure grpcStarted is set to true during channel initialization * Fix sendScrapeResults to use trySend() for better error handling on closed channels * Refactor handleConnectionFailure to rethrow JVM Errors and improve error handling * Add overflow protection for chunkContentSizeBytes conversion and enhance tests * Add double-assignment protection to markComplete and enhance tests * Implement mergeContentTexts to handle OpenMetrics EOF markers and add corresponding tests * Enhance agent context invalidation logic to prevent premature invalidation of live agents during path registration * Add comprehensive bug summary and test coverage gap analysis for prometheus-proxy * Refactor AgentConnectionContext to support configurable backlog capacity and improve coroutine management in scrape request processing * Enhance scrape request management to fail requests on agent disconnection and during proxy shutdown * Implement unzipping logic with size limit and handle zip bomb exceptions in scrape request processing * Add configuration for maximum unzipped content size in megabytes * Handle HttpRequestTimeoutException in fetchScrapeUrl and ensure CancellationExceptions are rethrown appropriately * Add GEMINI.md for project overview and development conventions; create gemini-bugs-2-13-26.md for bug reporting * Reset scrapeRequestBacklogSize on connection attempt and handle backlog drift in sendScrapeRequestAction * Remove empty agentContexts from consolidated paths in ProxyPathManager * Add maxZippedContentSize parameter to ChunkedContext and validate content size in applyChunk * Add maxContentLengthMBytes parameter to limit scrape response size * Refactor tests and enhance exception handling in Agent and Proxy components * Add tests for dynamic configuration options in ProxyDynamicConfigTest * Add bug audit report for February 13, 2026, detailing fixes in Agent and Proxy components * Enhance errorCode() to walk cause chain for wrapped timeout exceptions Refactored errorCode() to utilize a new hasTimeoutCause() helper function that checks for wrapped timeout exceptions. Added comprehensive tests to cover various scenarios, including wrapped and deeply nested exceptions. * Update retry policy to only retry on server errors (5xx) and add tests for 4xx responses * Fix CancellationException handling in HttpClientCache cleanup coroutine and add tests * Fix mergeContentTexts to exclude empty content from failed agents and add tests * Fix log level for missing ScrapeRequestWrapper during timeouts and add tests * Fix redundant channel close in writeResponsesToProxyUntilDisconnected and add tests * Fix query param concatenation in fetchScrapeUrl and handle invalid gzip responses in submitScrapeRequest; add tests for both * Increase test scalability by adjusting query counts and add a helper function to start the server * Update configuration paths in documentation and code; move static analysis and config files to 'etc' directory * Update configuration classes and add new metrics options; improve structure and readability * Add Apache License 2.0 to the repository * Add XML declaration to misc.xml for proper parsing * Refactor CLAUDE.md to improve structure and readability; consolidate build commands and testing instructions * Add support for environment variables from secrets file; update .gitignore and XML declaration * Update copyright year to 2026 in multiple files * Remove outdated copyright notice from logback configuration files * Refactor tests to use HARNESS_CONFIG for configuration values; improve readability and consistency * Fix OPTIONS_CONFIG path logic to correctly prepend GH_PREFIX based on JUNIT_FILE existence * Update UtilsTest to use Level for log level management; remove unused imports * Change maxZippedContentSize type to Long to prevent Int overflow; add tests for large values * Fix sendHeartBeat to re-throw NOT_FOUND status for proper reconnection handling; add tests for error propagation * Fix transportFilterDisabled mismatch handling to throw StatusException with FAILED_PRECONDITION; update tests for correct error propagation * Fix onHeaders behavior to cancel call when agent ID key is missing; update tests for correct cancellation and error handling * Fix URL logging to sanitize sensitive information; update tests for byte count discrepancies * Enhance resolveBoolean option handling to support explicit CLI flags; add tests for new behavior * Fix ProxyOptions to handle service discovery configuration correctly; add tests for sdEnabled behavior * Enhance resolveBooleanOption to support additional CLI flags for consolidated, keepAliveWithoutCalls, and trustAllX509Certificates; update related logging * Add sanitizeUrl function to strip credentials from URLs; include tests for various cases * Add 404 Not Found status code handling for invalid paths; include test for fetchScrapeUrl * Throw NOT_FOUND exception when agent context is missing; update tests to verify behavior * Fix high and medium-impact bugs in Prometheus Proxy; address integer overflow, zombie state, gRPC status mismatch, credential leak, content length check, CLI flag handling, and logging issues * Refactor update message handling in ProxyHttpRoutes; change updateMsg to updateMsgs for better support of multiple messages * Implement timeout handling in fetchContent; ensure total fetch time is bounded by scrapeTimeoutSecs and update tests for gzip threshold and retry behavior * Swap gzip and deflate priority values in ProxyHttpConfig; update tests to reflect changes in compression behavior * Enhance close() method in AgentConnectionContext to drain scrapeRequestActionsChannel and return the count of drained requests; update tests to verify behavior * Refactor AgentConnectionContext close() method to return drained request count; update scrapeRequestBacklogSize accordingly. Modify ProxyUtils to use updateMsgs as a list for error responses; adjust tests to verify changes. * Add support for "all" log level in setLogLevel; update tests to verify behavior * Implement atomic decrement for scrapeRequestBacklogSize to prevent negative values during concurrent operations; update close() method in AgentConnectionContext to return drained request count and adjust backlog accordingly. * Fix typo in path variable initialization in BasicHarnessTests * Add tests for decrementBacklog to ensure it clamps at zero and handles concurrency correctly * Fix agent context cleanup and shutdown ordering to prevent resource leaks and improve error messaging * Fix gzip compression for small responses by enforcing minimumSize(1024) in ProxyHttpConfig; add test to verify behavior * Refactor path registration to allow concurrent operations by moving gRPC calls outside of the mutex; update tests to verify behavior * Fix logging for agent context removal and improve handling of double removals; add tests to verify behavior * Fix applySummary to correctly propagate headerZipped value; update tests to verify behavior * Fix toScrapeResponseHeader to propagate srZipped value; add tests to verify behavior * Refactor tests to improve compile-time safety and enhance concurrency; update response handling for compression * Fix integer overflow in totalByteCount and ensure proper handling of large accumulated chunks; add tests to verify behavior * Fix input validation in ChunkedContext.applyChunk and address TOCTOU race in AgentContextCleanupService; add tests to verify behavior * Update README to reflect changes in log level options and correct servlet documentation URL * Update README to include proxy content size limits for chunked transfers * Add release notes for version 3.0.0 with bug fixes, new features, refactoring, and breaking changes * Remove Travis CI configuration as it is no longer in use * Rename RELEASE-NOTES.md to RELEASE_NOTES.md for consistency * Add improvements document outlining code quality, performance, security, and maintainability suggestions * Add KDoc documentation summary and README feedback for improved clarity and test coverage * Fix parseHostPort to remove brackets from IPv6 addresses in HostPort * Add KDoc documentation summary and test coverage details for Prometheus Proxy * Add KDoc documentation for agent connection and proxy services * Update KDoc summary to document internal service classes and improve test coverage suggestions * Add Dokka integration for API documentation generation * Add documentation for Prometheus Proxy module and its packages * Update KDoc references to use fully qualified names for Agent and Proxy classes * Add GitHub Actions workflow for deploying Dokka documentation to GitHub Pages * Add CI workflow for building the project using GitHub Actions * Add GitHub Actions CI workflow for building and deploying documentation * Add environment variable for Harness configuration in CI workflow * Update CI workflow to skip tests during build and run specific tests for Prometheus components * Comment out specific test runs for Prometheus components in CI workflow
| Commit: | 0db8810 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.23.0 (#101) * Update to Kotlin 2.1.0, Ktor 3.0.1, and gRPC 1.68.2 * Change minimum JDK from 17 to 11 * Remove krotodc library * Convert build.gradle to build.gradle.kts * Add support for gRPC reflection * Add support for service discovery labels in pathConfigs
The documentation is generated from this commit.
| Commit: | b4f646d | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
Add support for using nginx as a reverse proxy for prometheus_proxy (#85)
| Commit: | ab4eafa | |
|---|---|---|
| Author: | Wolfgang Jung | |
| Committer: | GitHub | |
Adds Authorization Header to proxied requests (#70) * Adds Authorization Header to proxied requests For retrieving password/JWT-protected endpoints with the default prometheus mechanisms, the Authorization-Header is passed transparently from the request to the proxy-endpoint to the http call made by the agent. * Adds documentation to proxied Authorization Headers Authored-by: Wolfgang Jung <w.jung@polyas.de>
| Commit: | a1e8d04 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.7.1 * Make agent embeddable * Fix problem in agent cleanup removal
| Commit: | 29b870d | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.6.4 * Update jars * Add support for passing query params from proxy to agent
| Commit: | 7dd5441 | |
|---|---|---|
| Author: | pambrose | |
Add support for passing query params
| Commit: | 6f72a28 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.6.2 (#34) * Create 1.6.2 release * Rename NonChunkedScrapeResponse to ScrapeResponse * Rename NonChunkedScrapeResponse to ScrapeResponse * Add support for min gzip size * Add support for min gzip size * Add support for min gzip size * Add support for min gzip size * Add support for min gzip size * Add support for min gzip size
| Commit: | c3af2f5 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.6.1 * Zip chunked and non-chunked content
| Commit: | 39726dd | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.6.0 * Add support for large ScrapeResponse msgs
| Commit: | 4485c1f | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.4.5 * Add debug servlet
| Commit: | d2c5ed8 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.4.3 * Cleanup Agent
| Commit: | 6c25766 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
1.4.0 * Update jars * Add coroutines * Add ktor server * Update kotlin to 1.3.50 * Convert to Durations * Switch from maven to gradle * Split java and kotlin code into their respective dirs
| Commit: | d3b7616 | |
|---|---|---|
| Author: | Paul Ambrose | |
| Committer: | GitHub | |
Add Kotlin idioms * Kotlin conversion * Add AtomicDelegates
| Commit: | e330fac | |
|---|---|---|
| Author: | Paul Ambrose | |
Rename package
| Commit: | d2ce555 | |
|---|---|---|
| Author: | Paul Ambrose | |
Code cleanup
| Commit: | 6564095 | |
|---|---|---|
| Author: | Paul Ambrose | |
Add more tests
| Commit: | a70c4a7 | |
|---|---|---|
| Author: | Paul Ambrose | |
Add support travis tests
| Commit: | 4e38cd7 | |
|---|---|---|
| Author: | Paul Ambrose | |
Added support for removing inactive agents
| Commit: | 8e75d67 | |
|---|---|---|
| Author: | Paul Ambrose | |
Add agent heartbeat
| Commit: | 422d8dc | |
|---|---|---|
| Author: | Paul Ambrose | |
Add agent name
| Commit: | ed968c9 | |
|---|---|---|
| Author: | Paul Ambrose | |
Add zipkin trace for entire request
| Commit: | ace9a30 | |
|---|---|---|
| Author: | Paul Ambrose | |
Propagate accept and content_type header values
| Commit: | c97d7d9 | |
|---|---|---|
| Author: | Paul Ambrose | |
Convert scrape results call to stream
| Commit: | 6e33f4b | |
|---|---|---|
| Author: | Paul Ambrose | |
Add valid flag to responses
| Commit: | 3425873 | |
|---|---|---|
| Author: | Paul Ambrose | |
Convert to logback logging
| Commit: | af7e258 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | a8a7fe8 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 9c1e57b | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 2da5e6c | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 4d6de47 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | c3059f0 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 3fcafed | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 6df7aa5 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 2c46cc4 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 6999a30 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 7c0e98c | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 1e2de49 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | c7d10ae | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | 0d3a38a | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit
| Commit: | f879191 | |
|---|---|---|
| Author: | Paul Ambrose | |
Initial commit