-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add log-level filtering methods and associated refactoring: #12
Changes from 16 commits
398c23f
2292781
f69ee31
5b74422
8749844
782dd13
856ce4a
2937d8f
95379d6
773020f
b965d98
5b31d01
fbb3f7b
30e76a0
d878399
d2e3d1d
b1f1afd
0b3dd23
a1df31c
c3d13be
14d4977
f4d2fd8
cf093ee
09656b4
65a788f
ca2a0eb
a912eeb
b7c28c9
8f81a51
5be8974
fce620e
47b9fed
cf8c036
e8b732c
a273e33
0a09a45
ed140f1
81e7739
e967005
55dabd4
bd0371a
1c4ab88
2b946ba
c04d887
bab5036
b3fde47
7564280
7d01cf2
bd29b8f
a244f5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#ifndef CLP_FFI_JS_IR_LOG_VIEWER_EVENT_HPP | ||
#define CLP_FFI_JS_IR_LOG_VIEWER_EVENT_HPP | ||
|
||
#include <clp/ir/LogEvent.hpp> | ||
#include <utility> | ||
|
||
namespace clp_ffi_js::ir { | ||
|
||
/** | ||
* A class derived from LogEvent with an additional member for log level. | ||
* @tparam encoded_variable_t The type of encoded variables in the event | ||
*/ | ||
template <typename encoded_variable_t> | ||
class LogViewerEvent : public clp::ir::LogEvent<encoded_variable_t> { | ||
public: | ||
// Constructors | ||
LogViewerEvent( | ||
clp::ir::epoch_time_ms_t timestamp, | ||
clp::UtcOffset utc_offset, | ||
clp::ir::EncodedTextAst<encoded_variable_t> message, | ||
size_t log_level | ||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
: clp::ir::LogEvent<encoded_variable_t>(timestamp, utc_offset, std::move(message)), | ||
m_log_level{log_level} {} | ||
|
||
// Methods | ||
[[nodiscard]] auto get_log_level() const -> size_t; | ||
|
||
private: | ||
size_t m_log_level; | ||
}; | ||
|
||
template <typename encoded_variable_t> | ||
auto LogViewerEvent<encoded_variable_t>::get_log_level() const -> size_t { | ||
return m_log_level; | ||
} | ||
} // namespace clp_ffi_js::ir | ||
|
||
#endif // CLP_FFI_JS_IR_LOG_VIEWER_EVENT_HPP |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,6 +5,7 @@ | |||||||||||||||||||||||
#include <cstdint> | ||||||||||||||||||||||||
#include <iterator> | ||||||||||||||||||||||||
#include <memory> | ||||||||||||||||||||||||
#include <optional> | ||||||||||||||||||||||||
#include <span> | ||||||||||||||||||||||||
#include <string> | ||||||||||||||||||||||||
#include <string_view> | ||||||||||||||||||||||||
|
@@ -15,7 +16,6 @@ | |||||||||||||||||||||||
#include <clp/Array.hpp> | ||||||||||||||||||||||||
#include <clp/ErrorCode.hpp> | ||||||||||||||||||||||||
#include <clp/ffi/ir_stream/decoding_methods.hpp> | ||||||||||||||||||||||||
#include <clp/ir/LogEvent.hpp> | ||||||||||||||||||||||||
#include <clp/ir/LogEventDeserializer.hpp> | ||||||||||||||||||||||||
#include <clp/ir/types.hpp> | ||||||||||||||||||||||||
#include <clp/streaming_compression/zstd/Decompressor.hpp> | ||||||||||||||||||||||||
|
@@ -26,6 +26,7 @@ | |||||||||||||||||||||||
|
||||||||||||||||||||||||
#include <clp_ffi_js/ClpFfiJsException.hpp> | ||||||||||||||||||||||||
#include <clp_ffi_js/constants.hpp> | ||||||||||||||||||||||||
#include <clp_ffi_js/ir/LogViewerEvent.hpp> | ||||||||||||||||||||||||
#include <clp_ffi_js/ir/StreamReaderDataContext.hpp> | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
using namespace std::literals::string_literals; | ||||||||||||||||||||||||
|
@@ -99,23 +100,58 @@ auto StreamReader::get_num_events_buffered() const -> size_t { | |||||||||||||||||||||||
return m_encoded_log_events.size(); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
auto StreamReader::deserialize_range(size_t begin_idx, size_t end_idx) -> size_t { | ||||||||||||||||||||||||
constexpr size_t cFullRangeEndIdx{0}; | ||||||||||||||||||||||||
if (0 != begin_idx || cFullRangeEndIdx != end_idx) { | ||||||||||||||||||||||||
throw ClpFfiJsException{ | ||||||||||||||||||||||||
clp::ErrorCode::ErrorCode_Unsupported, | ||||||||||||||||||||||||
__FILENAME__, | ||||||||||||||||||||||||
__LINE__, | ||||||||||||||||||||||||
"Partial range deserialization is not yet supported." | ||||||||||||||||||||||||
}; | ||||||||||||||||||||||||
auto StreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapType { | ||||||||||||||||||||||||
if (std::nullopt == m_filtered_log_event_map) { | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
return FilteredLogEventMapType(emscripten::val::null()); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
return FilteredLogEventMapType(emscripten::val::array(m_filtered_log_event_map.value())); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
auto StreamReader::build() -> size_t { | ||||||||||||||||||||||||
if (nullptr != m_stream_reader_data_context) { | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use an early return to reduce indentation. |
||||||||||||||||||||||||
constexpr size_t cDefaultNumReservedLogEvents{500'000}; | ||||||||||||||||||||||||
m_encoded_log_events.reserve(cDefaultNumReservedLogEvents); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
std::string logtype; | ||||||||||||||||||||||||
constexpr size_t cDefaultReservedMessageLength{512}; | ||||||||||||||||||||||||
logtype.reserve(cDefaultReservedMessageLength); | ||||||||||||||||||||||||
while (true) { | ||||||||||||||||||||||||
auto result{m_stream_reader_data_context->get_deserializer().deserialize_log_event()}; | ||||||||||||||||||||||||
if (false == result.has_error()) { | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that the positive case handling is much longer, shall we flip the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||||||||||||||||||||
m_encoded_log_events.emplace_back(std::move(result.value())); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const auto log_event = result.value(); | ||||||||||||||||||||||||
const auto message = log_event.get_message(); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
logtype.clear(); | ||||||||||||||||||||||||
logtype = message.get_logtype(); | ||||||||||||||||||||||||
junhaoliao marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need the upper-level declaration of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I copied this from the code for message in decode() see |
||||||||||||||||||||||||
|
||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
constexpr size_t cLogLevelPositionInMessages{1}; | ||||||||||||||||||||||||
if (logtype.length() < cLogLevelPositionInMessages) { | ||||||||||||||||||||||||
SPDLOG_ERROR("Failed to extract log type for log level parsing."); break; | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
size_t log_level{cLogLevelNone}; | ||||||||||||||||||||||||
// NOLINTNEXTLINE(readability-qualified-auto) | ||||||||||||||||||||||||
auto const log_level_name_it{std::find_if( | ||||||||||||||||||||||||
cLogLevelNames.begin() + cValidLogLevelsBeginIdx, | ||||||||||||||||||||||||
cLogLevelNames.end(), | ||||||||||||||||||||||||
[&](std::string_view level) { | ||||||||||||||||||||||||
return logtype.substr(cLogLevelPositionInMessages).starts_with(level); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
)}; | ||||||||||||||||||||||||
if (log_level_name_it != cLogLevelNames.end()) { | ||||||||||||||||||||||||
log_level = std::distance(cLogLevelNames.begin(), log_level_name_it); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const auto log_viewer_event = LogViewerEvent<four_byte_encoded_variable_t>( | ||||||||||||||||||||||||
log_event.get_timestamp(), | ||||||||||||||||||||||||
log_event.get_utc_offset(), | ||||||||||||||||||||||||
message, | ||||||||||||||||||||||||
log_level | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
m_encoded_log_events.emplace_back(std::move(log_viewer_event)); | ||||||||||||||||||||||||
continue; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
auto const error{result.error()}; | ||||||||||||||||||||||||
|
@@ -135,27 +171,38 @@ auto StreamReader::deserialize_range(size_t begin_idx, size_t end_idx) -> size_t | |||||||||||||||||||||||
} | ||||||||||||||||||||||||
m_stream_reader_data_context.reset(nullptr); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If not intentional, let's revert this line removal. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||||||||||||||||||||
return m_encoded_log_events.size(); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
auto StreamReader::decode_range(size_t begin_idx, size_t end_idx) const -> DecodedResultsTsType { | ||||||||||||||||||||||||
if (m_encoded_log_events.size() < end_idx || begin_idx >= end_idx) { | ||||||||||||||||||||||||
auto StreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const -> DecodedResultsTsType { | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
if (use_filter && (std::nullopt == m_filtered_log_event_map)) { | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
return DecodedResultsTsType(emscripten::val::null()); | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
std::span const log_events_span{ | ||||||||||||||||||||||||
m_encoded_log_events.begin() | ||||||||||||||||||||||||
+ static_cast<decltype(m_encoded_log_events)::difference_type>(begin_idx), | ||||||||||||||||||||||||
m_encoded_log_events.begin() | ||||||||||||||||||||||||
+ static_cast<decltype(m_encoded_log_events)::difference_type>(end_idx) | ||||||||||||||||||||||||
}; | ||||||||||||||||||||||||
size_t length; | ||||||||||||||||||||||||
if (use_filter) { | ||||||||||||||||||||||||
length = m_filtered_log_event_map->size(); | ||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||
length = m_encoded_log_events.size(); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
if (length < end_idx || 0 > begin_idx) { | ||||||||||||||||||||||||
junhaoliao marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As 🐰 mentioned, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🥕 -> 🐰 |
||||||||||||||||||||||||
return DecodedResultsTsType(emscripten::val::null()); | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
} | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
std::string message; | ||||||||||||||||||||||||
constexpr size_t cDefaultReservedMessageLength{512}; | ||||||||||||||||||||||||
message.reserve(cDefaultReservedMessageLength); | ||||||||||||||||||||||||
size_t log_num{begin_idx + 1}; | ||||||||||||||||||||||||
auto const results{emscripten::val::array()}; | ||||||||||||||||||||||||
for (auto const& log_event : log_events_span) { | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
for (size_t i = begin_idx; i < end_idx; ++i) { | ||||||||||||||||||||||||
size_t log_event_idx; | ||||||||||||||||||||||||
if (use_filter) { | ||||||||||||||||||||||||
log_event_idx = m_filtered_log_event_map->at(i); | ||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||
log_event_idx = i; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
const auto& log_event = m_encoded_log_events[log_event_idx]; | ||||||||||||||||||||||||
message.clear(); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
auto const parsed{log_event.get_message().decode_and_unparse()}; | ||||||||||||||||||||||||
|
@@ -165,36 +212,38 @@ auto StreamReader::decode_range(size_t begin_idx, size_t end_idx) const -> Decod | |||||||||||||||||||||||
} | ||||||||||||||||||||||||
message.append(parsed.value()); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
constexpr size_t cLogLevelPositionInMessages{1}; | ||||||||||||||||||||||||
size_t log_level{cLogLevelNone}; | ||||||||||||||||||||||||
// NOLINTNEXTLINE(readability-qualified-auto) | ||||||||||||||||||||||||
auto const log_level_name_it{std::find_if( | ||||||||||||||||||||||||
cLogLevelNames.begin() + cValidLogLevelsBeginIdx, | ||||||||||||||||||||||||
cLogLevelNames.end(), | ||||||||||||||||||||||||
[&](std::string_view level) { | ||||||||||||||||||||||||
return message.substr(cLogLevelPositionInMessages).starts_with(level); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
)}; | ||||||||||||||||||||||||
if (log_level_name_it != cLogLevelNames.end()) { | ||||||||||||||||||||||||
log_level = std::distance(cLogLevelNames.begin(), log_level_name_it); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
m_ts_pattern.insert_formatted_timestamp(log_event.get_timestamp(), message); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
EM_ASM( | ||||||||||||||||||||||||
{ Emval.toValue($0).push([UTF8ToString($1), $2, $3, $4]); }, | ||||||||||||||||||||||||
results.as_handle(), | ||||||||||||||||||||||||
message.c_str(), | ||||||||||||||||||||||||
log_event.get_timestamp(), | ||||||||||||||||||||||||
log_level, | ||||||||||||||||||||||||
log_num | ||||||||||||||||||||||||
log_event.get_log_level(), | ||||||||||||||||||||||||
log_event_idx +1 | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
++log_num; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
return DecodedResultsTsType(results); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
void StreamReader::filter_log_events(const emscripten::val& logLevelFilter) { | ||||||||||||||||||||||||
if (logLevelFilter.isNull()) { | ||||||||||||||||||||||||
m_filtered_log_event_map.reset(); | ||||||||||||||||||||||||
return; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
m_filtered_log_event_map.emplace(); | ||||||||||||||||||||||||
std::vector<int> filter_levels = emscripten::vecFromJSArray<int>(logLevelFilter); | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
for (size_t index = 0; index < m_encoded_log_events.size(); ++index) { | ||||||||||||||||||||||||
const auto& logEvent = m_encoded_log_events[index]; | ||||||||||||||||||||||||
if (std::find(filter_levels.begin(), filter_levels.end(), logEvent.get_log_level()) != filter_levels.end()) { | ||||||||||||||||||||||||
m_filtered_log_event_map->push_back(index); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reverting back to previous. I dont think most people are using c++23 yet, so not sure we want to use std::views::enumerate |
||||||||||||||||||||||||
} | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Optimization suggestion for The Replace the linear search with a more efficient data structure for log level lookup. Using an Here's a suggested optimization: void StreamReader::filter_log_events(const emscripten::val& logLevelFilter) {
if (logLevelFilter.isNull()) {
m_filtered_log_event_map.reset();
return;
}
m_filtered_log_event_map.emplace();
std::unordered_set<int> filter_levels(emscripten::vecFromJSArray<int>(logLevelFilter).begin(),
emscripten::vecFromJSArray<int>(logLevelFilter).end());
for (size_t index = 0; index < m_encoded_log_events.size(); ++index) {
const auto& logEvent = m_encoded_log_events[index];
if (filter_levels.count(logEvent.get_log_level()) > 0) {
m_filtered_log_event_map->push_back(index);
}
}
} This change reduces the time complexity of the level lookup from O(n) to O(1), where n is the number of filter levels. |
||||||||||||||||||||||||
|
||||||||||||||||||||||||
StreamReader::StreamReader( | ||||||||||||||||||||||||
StreamReaderDataContext<four_byte_encoded_variable_t>&& stream_reader_data_context | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
|
@@ -211,6 +260,10 @@ EMSCRIPTEN_BINDINGS(ClpIrStreamReader) { | |||||||||||||||||||||||
emscripten::register_type<clp_ffi_js::ir::DecodedResultsTsType>( | ||||||||||||||||||||||||
"Array<[string, number, number, number]>" | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
emscripten::register_type<clp_ffi_js::ir::FilteredLogEventMapType>( | ||||||||||||||||||||||||
"number[]" | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
emscripten::class_<clp_ffi_js::ir::StreamReader>("ClpIrStreamReader") | ||||||||||||||||||||||||
.constructor( | ||||||||||||||||||||||||
&clp_ffi_js::ir::StreamReader::create, | ||||||||||||||||||||||||
|
@@ -220,7 +273,9 @@ EMSCRIPTEN_BINDINGS(ClpIrStreamReader) { | |||||||||||||||||||||||
"getNumEventsBuffered", | ||||||||||||||||||||||||
&clp_ffi_js::ir::StreamReader::get_num_events_buffered | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
.function("deserializeRange", &clp_ffi_js::ir::StreamReader::deserialize_range) | ||||||||||||||||||||||||
.function("decodeRange", &clp_ffi_js::ir::StreamReader::decode_range); | ||||||||||||||||||||||||
.function("getFilteredLogEventMap", &clp_ffi_js::ir::StreamReader::get_filtered_log_event_map) | ||||||||||||||||||||||||
.function("build", &clp_ffi_js::ir::StreamReader::build) | ||||||||||||||||||||||||
.function("decodeRange", &clp_ffi_js::ir::StreamReader::decode_range) | ||||||||||||||||||||||||
.function("filterLogEvents", &clp_ffi_js::ir::StreamReader::filter_log_events); | ||||||||||||||||||||||||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} // namespace |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
|
||
#include <cstddef> | ||
#include <memory> | ||
#include <optional> | ||
#include <vector> | ||
|
||
#include <clp/ir/LogEvent.hpp> | ||
|
@@ -12,10 +13,12 @@ | |
#include <emscripten/val.h> | ||
|
||
#include <clp_ffi_js/ir/StreamReaderDataContext.hpp> | ||
#include <clp_ffi_js/ir/LogViewerEvent.hpp> | ||
|
||
namespace clp_ffi_js::ir { | ||
EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); | ||
EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); | ||
EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapType); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be |
||
|
||
/** | ||
* Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded | ||
|
@@ -50,42 +53,54 @@ class StreamReader { | |
[[nodiscard]] auto get_num_events_buffered() const -> size_t; | ||
|
||
/** | ||
* Deserializes and buffers log events in the range `[beginIdx, endIdx)`. After the stream has | ||
* been exhausted, it will be deallocated. | ||
* @return The filtered log events map. | ||
*/ | ||
[[nodiscard]] auto get_filtered_log_event_map() const -> FilteredLogEventMapType; | ||
|
||
/** | ||
* Filters log events and generates `m_filtered_log_event_map`. If `logLevelFilter` is `null`, | ||
* `m_filtered_log_event_map` will be set to `std::nullopt`. | ||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* NOTE: Currently, this class only supports deserializing the full range of log events in the | ||
* stream. | ||
* @param logLevelFilter Array of selected log levels | ||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
void filter_log_events(const emscripten::val& logLevelFilter); | ||
|
||
/** | ||
* Deserializes all log events in the file. After the stream has been exhausted, it will be | ||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* deallocated. | ||
* | ||
* @param begin_idx | ||
* @param end_idx | ||
* @return The number of successfully deserialized ("valid") log events. | ||
*/ | ||
[[nodiscard]] auto deserialize_range(size_t begin_idx, size_t end_idx) -> size_t; | ||
[[nodiscard]] auto build() -> size_t; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am okay with this, but also consider the fact i don't really believe this code base is a "generic ir library". For example, clp-ffi-go exposes more general functions and presents itself as a go wrapper for the c++ ir library. The functions in this code base are very specific to log viewer and appear to really be an accelerator for a js implemetation of log viewer irDecoder. From this perspective, build() is more appropriate. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For example I could not build a js implementation of fluent-bit-clp with this "ir library" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, but this library needs to start somewhere and we don't have time to implement all of the IR methods right now, right? It would also waste more time to create a log-viewer-specific accelerator library just to eventually throw it away and replace it with this library. Fwiw, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay my opinions are not so strong here. I am happy with deserialize_stream. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done!
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* Decodes the deserialized log events in the range `[beginIdx, endIdx)`. | ||
* Decodes log events in the range `[beginIdx, endIdx)` of the filtered or unfiltered | ||
* (depending on the value of `useFilter`) log events collection. | ||
* | ||
* @param begin_idx | ||
* @param end_idx | ||
* @param use_filter Whether to decode from the filtered or unfiltered log events collection. | ||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @return An array where each element is a decoded log event represented by an array of: | ||
* - The log event's message | ||
* - The log event's timestamp as milliseconds since the Unix epoch | ||
* - The log event's log level as an integer that indexes into `cLogLevelNames` | ||
* - The log event's number (1-indexed) in the stream | ||
* @return null if any log event in the range doesn't exist (e.g., the range exceeds the number | ||
* of log events in the file). | ||
* of log events in collection) | ||
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
[[nodiscard]] auto decode_range(size_t begin_idx, size_t end_idx) const -> DecodedResultsTsType; | ||
[[nodiscard]] auto decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const -> DecodedResultsTsType; | ||
|
||
|
||
private: | ||
// Constructor | ||
explicit StreamReader(StreamReaderDataContext<clp::ir::four_byte_encoded_variable_t>&& | ||
stream_reader_data_context); | ||
|
||
// Variables | ||
std::vector<clp::ir::LogEvent<clp::ir::four_byte_encoded_variable_t>> m_encoded_log_events; | ||
std::vector<LogViewerEvent<clp::ir::four_byte_encoded_variable_t>> m_encoded_log_events; | ||
std::unique_ptr<StreamReaderDataContext<clp::ir::four_byte_encoded_variable_t>> | ||
m_stream_reader_data_context; | ||
m_stream_reader_data_context; | ||
std::optional<std::vector<size_t>> m_filtered_log_event_map; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update member variables for new functionality The changes to However, std::optional<std::vector<size_t>> m_filtered_log_event_map{};
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's replace the type with a type we define at the top of the class. /**
* Mapping between an index in the filtered log events collection to an index in the unfiltered
* log events collection.
*/
using FilteredLogEventsMap = std::optional<std::vector<size_t>>; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
clp::TimestampPattern m_ts_pattern; | ||
}; | ||
} // namespace clp_ffi_js::ir | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make more sense to name this as
LogEventExt
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(As in we might want to be less specific about the Log Viewer which is a final product. ) If done correctly, in the future we can release clp-ffi-js as a Node.js library and the extended attributes like the log level are still useful, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we call it
LogEventWithLevel
? I prefer to pick a strangely specific name because eventually, once we move to the next IR format, LogEvent (which will be a set of kv-pairs) should have a field which is its level. So by picking an odd name now, I think it will hint to the reader that this code has something odd about it and they will look more into the docstring (where we can explain the situation).