mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-06 08:09:24 +00:00
fix(rum): include unlinked session traces and filter polling noise (#14156)
This commit is contained in:
@@ -1255,11 +1255,6 @@ describe("PlayerTracesTab", () => {
|
||||
// =========================================================================
|
||||
// SQL is schema-guarded so a mobile stream never 400s
|
||||
//
|
||||
// Mobile RUM streams lack the browser-shaped view columns: `view_loading_type`
|
||||
// is browser-only, and `action_id` may be absent. Referencing a column the
|
||||
// stream does not have fails the whole query with a 400. Every optional column
|
||||
// must therefore be selected only when present, and the `action_id` filter
|
||||
// applied only when that column exists.
|
||||
// =========================================================================
|
||||
|
||||
describe("schema-guarded SQL", () => {
|
||||
@@ -1268,9 +1263,7 @@ describe("PlayerTracesTab", () => {
|
||||
return call?.[0]?.query?.query?.sql ?? "";
|
||||
}
|
||||
|
||||
it("omits view_loading_type and the action_id filter on a mobile schema", async () => {
|
||||
// Arrange: a mobile-shaped schema — trace_id present, but no view_loading_type
|
||||
// and no action_id.
|
||||
it("omits browser-only fields and filters on a mobile schema", async () => {
|
||||
wrapper.unmount();
|
||||
mockSearch.mockClear();
|
||||
mockGetStream.mockResolvedValueOnce({
|
||||
@@ -1294,11 +1287,12 @@ describe("PlayerTracesTab", () => {
|
||||
expect(sql).not.toContain("max(view_loading_type)");
|
||||
expect(sql).toContain("NULL as _view_loading_type");
|
||||
expect(sql).not.toContain("action_id is not null");
|
||||
expect(sql).not.toContain("resource_url");
|
||||
expect(sql).toContain("_o2_trace_id");
|
||||
expect(sql).toContain("max(view_url)");
|
||||
});
|
||||
|
||||
it("keeps view_loading_type and the action_id filter on a full browser schema", async () => {
|
||||
it("includes unlinked traces and filters Socket.IO groups on a browser schema", async () => {
|
||||
// Arrange: browser schema carries every column.
|
||||
wrapper.unmount();
|
||||
mockSearch.mockClear();
|
||||
@@ -1312,6 +1306,7 @@ describe("PlayerTracesTab", () => {
|
||||
{ name: "type" },
|
||||
{ name: "date" },
|
||||
{ name: "action_id" },
|
||||
{ name: "resource_url" },
|
||||
],
|
||||
});
|
||||
|
||||
@@ -1322,7 +1317,26 @@ describe("PlayerTracesTab", () => {
|
||||
// Assert
|
||||
const sql = lastRumSql();
|
||||
expect(sql).toContain("max(view_loading_type) as _view_loading_type");
|
||||
expect(sql).toContain("action_id is not null");
|
||||
expect(sql).not.toContain("action_id is not null");
|
||||
expect(sql).toContain(
|
||||
"HAVING MAX(CASE WHEN resource_url LIKE '%/socket.io/%' AND resource_url LIKE '%transport=polling%' THEN 1 ELSE 0 END) = 0",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps null resource URLs while excluding a trace containing Socket.IO polling", async () => {
|
||||
wrapper.unmount();
|
||||
mockSearch.mockClear();
|
||||
mockGetStream.mockResolvedValueOnce({
|
||||
schema: [{ name: "_oo_trace_id" }, { name: "session_id" }, { name: "resource_url" }],
|
||||
});
|
||||
|
||||
wrapper = mountComponent();
|
||||
await flushPromises();
|
||||
|
||||
const sql = lastRumSql();
|
||||
expect(sql).not.toContain("resource_url NOT LIKE");
|
||||
expect(sql).toContain("resource_url LIKE '%/socket.io/%'");
|
||||
expect(sql).toContain("resource_url LIKE '%transport=polling%'");
|
||||
});
|
||||
|
||||
it("does not query at all when the stream has no trace_id column", async () => {
|
||||
|
||||
@@ -531,11 +531,7 @@ async function fetchTraces() {
|
||||
return;
|
||||
}
|
||||
|
||||
// The view-context columns are browser-shaped and are NOT guaranteed on a mobile
|
||||
// `_rumdata` schema. Referencing a column the stream lacks fails the whole query with a
|
||||
// 400, so each optional column is selected only when present (NULL-aliased otherwise)
|
||||
// and the `action_id` filter is applied only when that column exists. `session_id` and
|
||||
// the guarded `trace_id` are the only hard requirements.
|
||||
// Optional browser fields must be schema-guarded because mobile streams omit them.
|
||||
const presentCols = new Set((rumStream?.schema ?? []).map((field: any) => field?.name));
|
||||
const has = (col: string): boolean => presentCols.has(col);
|
||||
const aggOrNull = (fn: string, col: string, alias: string): string =>
|
||||
@@ -550,11 +546,13 @@ async function fetchTraces() {
|
||||
aggOrNull("min", "date", "_date"),
|
||||
];
|
||||
const whereParts = [`session_id='${props.sessionId}'`, traceIdSet];
|
||||
if (has("action_id")) whereParts.push("action_id is not null");
|
||||
const having = has("resource_url")
|
||||
? " HAVING MAX(CASE WHEN resource_url LIKE '%/socket.io/%' AND resource_url LIKE '%transport=polling%' THEN 1 ELSE 0 END) = 0"
|
||||
: "";
|
||||
|
||||
const rumQuery = {
|
||||
query: {
|
||||
sql: `SELECT ${selectParts.join(", ")} FROM "_rumdata" WHERE ${whereParts.join(" AND ")} GROUP BY ${traceIdExpr} ORDER BY _date ASC`,
|
||||
sql: `SELECT ${selectParts.join(", ")} FROM "_rumdata" WHERE ${whereParts.join(" AND ")} GROUP BY ${traceIdExpr}${having} ORDER BY _date ASC`,
|
||||
start_time: searchStartTime,
|
||||
end_time: searchEndTime,
|
||||
from: 0,
|
||||
|
||||
Reference in New Issue
Block a user