Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
43a3903
feat(clp-s): Support count and count-by-time aggregation output to th…
davemarco Jun 11, 2026
806aacd
Merge branch 'main' into clp-s-count-to-results-cache
davemarco Jun 11, 2026
33ad6b7
refactor(clp-s): Clean up count aggregation code to better match proj…
davemarco Jun 11, 2026
4b6a39a
docs(clp-s): Clarify that the existing count aggregation example in t…
davemarco Jun 11, 2026
8ed417a
refactor(clp-s): Rename count output handlers to indicate their desti…
davemarco Jun 12, 2026
7455500
feat(clp-s): Support count and count-by-time aggregation output to st…
Jun 18, 2026
61f9848
Address review comments.
davemarco Jun 22, 2026
a0f3622
Use `string const&` for results-cache count handler uri/collection pa…
davemarco Jun 22, 2026
1c282e6
Add forward declaration for results-cache helper and apply clang-format.
davemarco Jun 22, 2026
228e31a
Add ms unit to count_by_time_bucket_size field name.
davemarco Jun 22, 2026
d0f097b
Address review comments.
davemarco Jun 22, 2026
f95b1f6
Use `string const&` for results-cache count handler uri/collection pa…
davemarco Jun 22, 2026
20bddad
Add forward declaration for results-cache helper and apply clang-format.
davemarco Jun 22, 2026
f2aa7e3
Add ms unit to count_by_time_bucket_size field name.
davemarco Jun 22, 2026
f93586a
feat(clp-s): Support min and max aggregation output to stdout and the…
davemarco Jun 22, 2026
0e22223
Merge branch 'main' into clp-s-count-to-results-cache
davidlion Jun 24, 2026
e4b5c7b
refactor(clp-s): Address review comments on results-cache count handl…
davemarco Jun 25, 2026
f1a7ab7
refactor(clp-s): Apply clang-format to connect_to_results_cache signa…
davemarco Jun 25, 2026
79bea6f
Carry the results-cache count review fixes into the stdout aggregatio…
davemarco Jun 25, 2026
704ccf5
Separate aggregation operator args from output handler args.
davemarco Jun 25, 2026
79fda75
Drop now-unused default subcommand from collect_subcommands.
davemarco Jun 25, 2026
77ce3d8
Clean up leftover stdout output-handler code.
davemarco Jun 25, 2026
d4ee4b3
Validate aggregation support in each output handler's parse function.
davemarco Jun 25, 2026
47b13da
Drop redundant comment on aggregation members.
davemarco Jun 25, 2026
135a6d9
Select stdout aggregation by type instead of a bool flag.
davemarco Jun 25, 2026
abefa20
Split stdout aggregation into per-aggregation handlers.
davemarco Jun 25, 2026
ca08583
Rename stdout count handlers to match siblings and drop unused include.
davemarco Jun 25, 2026
c399b13
Merge main into stdout.
davemarco Jun 25, 2026
6ef3aa9
Reject unrecognized stdout output handler options.
davemarco Jun 25, 2026
8381d82
Generalize aggregation output handler comments and drop unused include.
davemarco Jun 25, 2026
29f786c
Merge stdout into min-max (sync onto current baseline; min/max reimpl…
davemarco Jun 25, 2026
4c5e4ca
Reimplement aggregations as a variant of aggregators with decoupled o…
davemarco Jun 25, 2026
06a0f8e
Extract aggregation sinks and results-cache connect helper into their…
davemarco Jun 26, 2026
dc20723
Throw on malformed min/max field and trim aggregation comments.
davemarco Jun 28, 2026
85c9ebf
Compare min/max int64 and double operands exactly to avoid precision …
davemarco Jun 28, 2026
cc4be18
Extract exact int64/double comparison into NumericCompare.hpp.
davemarco Jun 28, 2026
b3db872
Cite SQLite's sqlite3IntFloatCompare as the basis for the exact compa…
davemarco Jun 28, 2026
c34494d
Trim aggregation comments.
davemarco Jun 28, 2026
8002b1b
Clarify copy/move comment and trim sink doc comments.
davemarco Jun 28, 2026
f538e6f
Clarify NumericCompare comments.
davemarco Jun 28, 2026
60baba9
Rename NumericCompare to IntFloatCompare and clarify its comments.
davemarco Jun 28, 2026
afe0518
Trim redundant IntFloatCompare comments.
davemarco Jun 28, 2026
1a3b902
Simplify aggregation handler comment and fix trailing whitespace/newl…
davemarco Jun 28, 2026
e95f81b
Use angle-bracket includes for new clp_s headers per the new guideline.
davemarco Jun 28, 2026
069a495
Address review: validate bucket size, clear flushed buffer, explicit …
davemarco Jun 28, 2026
d990339
Move results-cache connect helper into a .cpp so the header lints und…
davemarco Jun 29, 2026
540c467
Merge main and keep my aggregation code
davemarco Jun 29, 2026
255d577
Merge branch 'main' into min-max
davidlion Jul 1, 2026
e56b93f
Constrain aggregators with a concept and template the output handler;…
davemarco Jul 2, 2026
13ac1ac
Clean up aggregation doc comments
davemarco Jul 3, 2026
f1d1dc4
Merge branch 'main' into min-max
davidlion Jul 6, 2026
31c7b0c
feat(clp-s): Support unique-value aggregation output to stdout and th…
davemarco Jul 6, 2026
7d2f35e
Collect boolean values in --unique and batch results-cache flushing.
davemarco Jul 6, 2026
e838098
refactor(clp-s): Address review feedback on min/max aggregation.
davemarco Jul 6, 2026
fdbc260
Document beats_extreme's candidate parameter.
davemarco Jul 7, 2026
11061c5
Correct Aggregator variant's doc comment to say "aggregators".
davemarco Jul 7, 2026
940ddcb
Reject min/max aggregation on namespaced fields and add a max usage e…
davemarco Jul 7, 2026
004951c
Merge branch 'main' into min-max
davidlion Jul 9, 2026
651c1ae
Rename Aggregation/IntFloatCompare files to snake_case and add member…
davemarco Jul 9, 2026
45a219e
Remove a redundant comment and an unused exception binding.
davemarco Jul 9, 2026
fcb16df
Merge remote-tracking branch 'origin/min-max' into uniqueimpl
davemarco Jul 9, 2026
3e351b1
Add --count-by group-by count aggregation to clp-s
davemarco Jul 13, 2026
63e6143
Merge remote-tracking branch 'upstream/main' into uniqueimpl
davemarco Jul 15, 2026
acad47e
Factor out node_to_aggregation_value helper and clarify flush-failure…
davemarco Jul 15, 2026
8da43ed
Extract shared JSON value helper and rename find_field_value
davemarco Jul 15, 2026
2d2f5c6
Add --unique usage example and tidy aggregation doc comments
davemarco Jul 15, 2026
04c6a15
docs(clp-s): trim redundant flush_buffer buffer-state comments
davemarco Jul 15, 2026
7d324f9
Merge branch 'uniqueimpl' into group-by-count
davemarco Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions components/core/src/clp_s/AggregationSink.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "AggregationSink.hpp"

#include <cstdint>
#include <iostream>
#include <string_view>
#include <variant>
Expand Down Expand Up @@ -27,12 +28,36 @@ auto StdoutSink::write(AggregationResult const& result) -> void {
std::cout << document.dump() << '\n';
}

ResultsCacheSink::ResultsCacheSink(string_view uri, string_view collection, string_view archive_id)
: m_archive_id{archive_id} {
ResultsCacheSink::ResultsCacheSink(
string_view uri,
string_view collection,
uint64_t batch_size,
string_view archive_id
)
: m_batch_size{batch_size},
m_archive_id{archive_id} {
m_collection = connect_to_results_cache(uri, collection, m_client);
}

auto ResultsCacheSink::flush_buffer() -> ErrorCode {
if (m_results.empty()) {
return ErrorCode::ErrorCodeSuccess;
}

try {
m_collection.insert_many(m_results);
} catch (mongocxx::exception const&) {
return ErrorCode::ErrorCodeFailureDbBulkWrite;
}
m_results.clear();
return ErrorCode::ErrorCodeSuccess;
}

auto ResultsCacheSink::write(AggregationResult const& result) -> void {
if (ErrorCode::ErrorCodeSuccess != m_flush_error) {
return;
}

bsoncxx::builder::basic::document document;
document.append(
bsoncxx::builder::basic::kvp(constants::results_cache::search::cArchiveId, m_archive_id)
Expand All @@ -46,19 +71,16 @@ auto ResultsCacheSink::write(AggregationResult const& result) -> void {
);
}
m_results.push_back(document.extract());
}

auto ResultsCacheSink::finish() -> ErrorCode {
if (m_results.empty()) {
return ErrorCode::ErrorCodeSuccess;
if (m_results.size() >= m_batch_size) {
m_flush_error = flush_buffer();
}
}

try {
m_collection.insert_many(m_results);
m_results.clear();
} catch (mongocxx::exception const& e) {
return ErrorCode::ErrorCodeFailureDbBulkWrite;
auto ResultsCacheSink::finish() -> ErrorCode {
if (ErrorCode::ErrorCodeSuccess != m_flush_error) {
return m_flush_error;
}
return ErrorCode::ErrorCodeSuccess;
return flush_buffer();
}
} // namespace clp_s
21 changes: 19 additions & 2 deletions components/core/src/clp_s/AggregationSink.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef CLP_S_AGGREGATIONSINK_HPP
#define CLP_S_AGGREGATIONSINK_HPP

#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
Expand Down Expand Up @@ -73,25 +74,41 @@ class ResultsCacheSink : public AggregationSink {
ResultsCacheSink(
std::string_view uri,
std::string_view collection,
uint64_t batch_size,
std::string_view archive_id
);

// Methods implementing AggregationSink
/**
* Buffers a result document, flushing the buffer to the database once it reaches the batch
* size. Documents are dropped after an earlier flush failure; the error surfaces in `finish()`.
* @param result The result document to write.
*/
auto write(AggregationResult const& result) -> void override;

/**
* Flushes the buffered result documents.
* Flushes any remaining buffered result documents.
* @return ErrorCodeSuccess on success
* @return ErrorCodeFailureDbBulkWrite on database error
* @return ErrorCodeFailureDbBulkWrite if this flush or an earlier batched flush failed
*/
[[nodiscard]] auto finish() -> ErrorCode override;

private:
// Methods
/**
* Inserts the buffered result documents into the collection.
* @return ErrorCodeSuccess on success
* @return ErrorCodeFailureDbBulkWrite on database error
*/
[[nodiscard]] auto flush_buffer() -> ErrorCode;

// Data members
mongocxx::client m_client;
mongocxx::collection m_collection;
uint64_t m_batch_size;
std::string m_archive_id;
std::vector<bsoncxx::document::value> m_results;
ErrorCode m_flush_error{ErrorCode::ErrorCodeSuccess};
};
} // namespace clp_s

Expand Down
38 changes: 34 additions & 4 deletions components/core/src/clp_s/CommandLineArguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,14 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) {
"max",
po::value<std::string>(&aggregation_field)->value_name("FIELD"),
"Find the maximum value of the given field"
)(
"unique",
po::value<std::string>(&aggregation_field)->value_name("FIELD"),
"Find the distinct values of the given field"
)(
"count-by",
po::value<std::string>(&aggregation_field)->value_name("FIELD"),
"Count the number of results grouped by the value of the given field"
);
// clang-format on
search_options.add(aggregation_options);
Expand Down Expand Up @@ -973,6 +981,14 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) {
<< std::endl;
std::cerr << " " << m_program_name << R"( s archives-dir "level: INFO")"
<< " --max latency" << std::endl;
std::cerr << std::endl;

std::cerr << " # Search archives in archives-dir for logs matching a KQL query"
R"( "level: INFO" and output the distinct values of field "latency")"
" to stdout"
<< std::endl;
std::cerr << " " << m_program_name << R"( s archives-dir "level: INFO")"
<< " --unique latency" << std::endl;

po::options_description visible_options;
visible_options.add(general_options);
Expand Down Expand Up @@ -1151,17 +1167,22 @@ auto CommandLineArguments::parse_aggregation_options(
auto const set_aggregator = [&](Aggregator value) {
if (aggregator.has_value()) {
throw std::invalid_argument(
"The --count, --count-by-time, --min, and --max options are mutually exclusive."
"The --count, --count-by-time, --min, --max, --unique, and --count-by options"
" are mutually exclusive."
);
}
aggregator = std::move(value);
};
auto const validate_aggregation_field = [&]() {
if (aggregation_field.empty()) {
throw std::invalid_argument("The --min and --max options require a field.");
throw std::invalid_argument(
"The --min, --max, --unique, and --count-by options require a field."
);
}
if (search::ast::has_unescaped_wildcards(aggregation_field)) {
throw std::invalid_argument("The --min and --max field must not contain wildcards.");
throw std::invalid_argument(
"The --min, --max, --unique, and --count-by field must not contain wildcards."
);
}
};

Expand All @@ -1182,6 +1203,14 @@ auto CommandLineArguments::parse_aggregation_options(
validate_aggregation_field();
set_aggregator(MinMaxAggregator{true, aggregation_field});
}
if (parsed_options.count("unique")) {
validate_aggregation_field();
set_aggregator(UniqueAggregator{aggregation_field});
}
if (parsed_options.count("count-by")) {
validate_aggregation_field();
set_aggregator(GroupByCountAggregator{aggregation_field});
}
return aggregator;
}

Expand Down Expand Up @@ -1225,7 +1254,8 @@ void CommandLineArguments::parse_reducer_output_handler_options(
}

if (false == m_aggregator.has_value()
|| std::holds_alternative<MinMaxAggregator>(m_aggregator.value()))
|| (false == std::holds_alternative<CountAggregator>(m_aggregator.value())
&& false == std::holds_alternative<CountByTimeAggregator>(m_aggregator.value())))
{
throw std::invalid_argument(
"The reducer output handler currently only supports count and count-by-time"
Expand Down
4 changes: 2 additions & 2 deletions components/core/src/clp_s/CommandLineArguments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ class CommandLineArguments {
* @param parsed_options
* @param count_by_time_bucket_size_millisecs Bucket size for count-by-time. Only used by that
* option.
* @param aggregation_field Field for min/max. Only used by those options.
* @param aggregation_field Field for min/max/unique. Only used by those options.
* @return The requested aggregation, or std::nullopt if none was requested.
* @throws std::invalid_argument if multiple aggregations are specified, the bucket size is
* non-positive, or a min/max field is empty or contains wildcards.
* non-positive, or a min/max/unique field is empty or contains wildcards.
*/
[[nodiscard]] static auto parse_aggregation_options(
boost::program_options::variables_map const& parsed_options,
Expand Down
Loading
Loading