fix: Add more fields to SearchHistoryHitResponse for search history and reuse it (#4702)

- Add `function`, `event`, `_timestamp` and `unit` to
`SearchHistoryHitResponse`.
- Only include `Search` events for search history
- Revert the change made in #4694 i.e. reuse `SearchHIstoryHitResponse`
for search history.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

- **New Features**
- Enhanced search history functionality with additional metadata fields
for more detailed responses.
	- Improved error handling and logging for search history operations.
- Updated data processing logic in the Search History component for
accurate representation of timestamps and durations.

- **Bug Fixes**
- Streamlined data processing and presentation in the Search History
component, ensuring accurate display of search history data.

- **Documentation**
- Updated component and method signatures to reflect changes in data
handling and structure.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Sai Nikhil <nikhil@openobserve.ai>
This commit is contained in:
Subhra264
2024-10-03 19:08:24 +05:30
committed by GitHub
co-authored by Sai Nikhil
parent 6f91cc8414
commit ea4b759fd9
3 changed files with 57 additions and 25 deletions
+22 -1
View File
@@ -446,6 +446,14 @@ pub struct SearchHistoryHitResponse {
pub response_time: f64,
pub cached_ratio: i64,
pub trace_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub function: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _timestamp: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unit: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub event: Option<String>,
}
impl TryFrom<json::Value> for SearchHistoryHitResponse {
@@ -502,6 +510,19 @@ impl TryFrom<json::Value> for SearchHistoryHitResponse {
.and_then(|v| v.as_str())
.ok_or("trace_id missing".to_string())?
.to_string(),
function: value
.get("function")
.and_then(|v| v.as_str())
.map(|v| v.to_string()),
_timestamp: value.get("_timestamp").and_then(|v| v.as_i64()),
unit: value
.get("unit")
.and_then(|v| v.as_str())
.map(|v| v.to_string()),
event: value
.get("event")
.and_then(|v| v.as_str())
.map(|v| v.to_string()),
})
}
}
@@ -993,7 +1014,7 @@ mod search_history_utils {
// Method to build the SQL query
pub fn build(self, search_stream_name: &str) -> String {
let mut query = format!("SELECT * FROM {} WHERE 1=1", search_stream_name);
let mut query = format!("SELECT * FROM {} WHERE event='Search'", search_stream_name);
if let Some(org_id) = self.org_id {
if !org_id.is_empty() {
+20 -2
View File
@@ -21,7 +21,7 @@ use chrono::{Duration, Utc};
use config::{
get_config,
meta::{
search::SearchEventType,
search::{SearchEventType, SearchHistoryHitResponse},
sql::resolve_stream_names,
stream::StreamType,
usage::{RequestStats, UsageType, USAGE_STREAM},
@@ -1435,7 +1435,7 @@ pub async fn search_partition(
"stream_type": "logs",
"took": 0.056222333,
"trace_id": "7f7898fd19424c47ba830a6fa9b25e1f",
"user_email": "root@example.com"
"function": ".",
},
],
"total": 3,
@@ -1558,6 +1558,24 @@ pub async fn search_history(
}
};
search_res.hits = search_res
.hits
.into_iter()
.filter_map(|hit| match SearchHistoryHitResponse::try_from(hit) {
Ok(response) => match serde_json::to_value(response) {
Ok(json_value) => Some(json_value),
Err(e) => {
log::error!("[trace_id {}] Serialization error: {:?}", trace_id, e);
None
}
},
Err(e) => {
log::error!("[trace_id {}] Deserialization error: {:?}", trace_id, e);
None
}
})
.collect::<Vec<_>>();
search_res.trace_id = trace_id.clone();
// report http metrics
+15 -22
View File
@@ -147,7 +147,7 @@
</div>
<div v-if="props.row?.function" class="text-left q-mb-sm tw-px-2 expanded-content">
<div class="tw-flex tw-items-center q-py-sm ">
<strong >Function Defination : <span> <q-btn
<strong >Function Definition : <span> <q-btn
@click.stop="copyToClipboard(props.row.function, 'Function Defination')"
size="xs"
dense
@@ -383,22 +383,22 @@
columnsToBeRendered.value = generateColumns(filteredHits);
filteredHits.forEach((hit:any)=>{
const {formatted, raw} = calculateDuration(hit.min_ts, hit.max_ts);
const {formatted, raw} = calculateDuration(hit.start_time, hit.end_time);
hit.duration = formatted;
hit.rawDuration = raw;
hit.toBeStoredStartTime = hit.min_ts;
hit.toBeStoredEndTime = hit.max_ts;
hit.start_time = timestampToTimezoneDate(hit.min_ts / 1000, store.state.timezone, "yyyy-MM-dd HH:mm:ss.SSS");
hit.end_time = timestampToTimezoneDate(hit.max_ts / 1000, store.state.timezone, "yyyy-MM-dd HH:mm:ss.SSS");
hit.rawTook = hit.response_time;
hit.took = formatTime(hit.response_time);
hit.scan_records = hit.num_records;
hit.rawScanRecords = hit.num_records;
hit.scan_size = hit.size + hit.unit;
hit.rawScanSize = hit.size;
hit.toBeStoredStartTime = hit.start_time;
hit.toBeStoredEndTime = hit.end_time;
hit.start_time = timestampToTimezoneDate(hit.start_time / 1000, store.state.timezone, "yyyy-MM-dd HH:mm:ss.SSS");
hit.end_time = timestampToTimezoneDate(hit.end_time / 1000, store.state.timezone, "yyyy-MM-dd HH:mm:ss.SSS");
hit.rawTook = hit.took;
hit.took = formatTime(hit.took);
hit.rawScanRecords = hit.scan_records;
hit.scan_records = hit.scan_records;
hit.rawScanSize = hit.scan_size;
hit.scan_size = hit.scan_size + hit.unit;
hit.cached_ratio = hit.cached_ratio;
hit.rawCachedRatio = hit.cached_ratio;
hit.sql = hit.request_body;
hit.sql = hit.sql;
hit.function = hit.function;
hit.rawExecutedTime = hit._timestamp;
hit.executed_time = timestampToTimezoneDate(hit._timestamp / 1000, store.state.timezone, "yyyy-MM-dd HH:mm:ss.SSS");
@@ -420,7 +420,7 @@
};
//this method needs to revamped / can be made shorter
const sortMethod = (rows, sortBy, descending) => {
const data = [...rows];
if(sortBy === 'duration'){
@@ -450,13 +450,6 @@
// console.log(data.sort((a, b) => a.rawScanRecords - b.rawScanRecords), "data")
return data.sort((a, b) => a.rawScanSize - b.rawScanSize);
}
if(sortBy === "scan_size"){
if (descending) {
return data.sort((a, b) => b.rawScanSize - a.rawScanSize);
}
// console.log(data.sort((a, b) => a.rawScanRecords - b.rawScanRecords), "data")
return data.sort((a, b) => a.rawScanSize - b.rawScanSize);
}
if(sortBy === "cached_ratio"){
if (descending) {
return data.sort((a, b) => b.rawCachedRatio - a.rawCachedRatio);
@@ -681,7 +674,7 @@
<style lang="scss" scoped >
.expanded-content {
padding: 0 3rem;
min-width: 100vh;
min-width: 100vw;
max-height: 100vh; /* Set a fixed height for the container */
overflow: hidden; /* Hide overflow by default */
}