diff --git a/README.md b/README.md index d3943a4..f53dc9a 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,9 @@ So the number of times something happened is the sum, over stored events, of `value` for events tagged `coalesced` and 1 for the rest — for a valueless event like `command`, simply `SUM(COALESCE(value, 1))`. Counting rows still works for "was it used, by how many servers"; it now undercounts "how many -times", by design. +times", by design. One exception: an event that already carries 32 tags, +or its own `coalesced` tag, has its count sent without the `coalesced` tag +(the server accepts at most 32), so that count reads as a single report. A minute is long enough that a command dispatched every tick is one event a minute instead of 1,200, and short enough that a person trying a command @@ -267,7 +269,8 @@ Shade it into a plugin jar; it is one class. `value` is omitted when not given, and when it is NaN or infinite (neither is JSON); `tags` always holds at least `version`, and -`install` whenever the client has an [installation ID](#every-event-carries-a-random-server-id). The server assigns the +`install` whenever the client has an [installation ID](#every-event-carries-a-random-server-id), and the count of a +[coalesced](#repeated-events-are-coalesced) event also carries `coalesced`. The server assigns the timestamp. A `201` is success; anything else is logged at `FINE` and dropped. Redirects are not followed. The body is streamed with a fixed length, so diff --git a/src/main/java/software/stephenson/trace/TraceClient.java b/src/main/java/software/stephenson/trace/TraceClient.java index b894591..f9967cc 100644 --- a/src/main/java/software/stephenson/trace/TraceClient.java +++ b/src/main/java/software/stephenson/trace/TraceClient.java @@ -40,7 +40,7 @@ * Reports usage events to a trace server, and never gets in the way of the * program doing the reporting. * - *
Three properties hold for every call to {@link #report}: + *
Four properties hold for every call to {@link #report}: * *
So the number of times an event happened is the sum, over the * events the server stored, of {@code value} where the * {@value #COALESCED_TAG} tag is present and 1 where it is not -- for - * a valueless event, simply {@code COALESCE(value, 1)}. + * a valueless event, simply {@code COALESCE(value, 1)}. The one + * exception: a count is not tagged when the event already carries + * {@value #MAX_TAGS} tags or its own {@value #COALESCED_TAG} tag, and + * such a count is then indistinguishable from a single report. * *
{@code startup} is never coalesced, nor held back: every one is * sent at once. @@ -920,10 +923,9 @@ int coalescing() { * Sends every count still being coalesced (see {@link #report(String, * Double, Map)}), then stops the sending thread, giving reports already * queued up to {@value #READ_TIMEOUT_MS} ms in total to be sent first. - * A program that - * reports and then exits within milliseconds -- a CLI -- would otherwise - * lose its one event to the race between queueing it and the thread - * picking it up. The bound still holds: an unreachable server delays exit + * A program that reports and then exits within milliseconds -- a CLI -- + * would otherwise lose its one event to the race between queueing it + * and the thread picking it up. The bound still holds: an unreachable server delays exit * by at most the timeout, never a hang; whatever has not been sent by * then is dropped. Safe to call more than once, and on a disabled client. */ @@ -1176,8 +1178,10 @@ public Builder installIdFile(File installIdFile) { * {@code [trace]}: a report the server did not answer {@code 201} * to or that could not be delivered, and a server-wide config or * install ID file that could not be read or written in - * {@link #build()}. A report dropped because the queue is full is - * not mentioned. Optional; without one, nothing is logged. + * {@link #build()}. A report dropped because the queue is full, or + * because {@value TraceClient#MAX_COALESCED_EVENTS} other events are + * already being counted, is not mentioned. Optional; without one, + * nothing is logged. */ public Builder logger(Logger logger) { this.logger = logger;