diff --git a/common/eventconsumption/eventindexhotspot.cpp b/common/eventconsumption/eventindexhotspot.cpp index 5358be7910f..63549527c4c 100644 --- a/common/eventconsumption/eventindexhotspot.cpp +++ b/common/eventconsumption/eventindexhotspot.cpp @@ -35,10 +35,17 @@ class CHotspotEventVisitor : public CInterfaceOf // The lowest and highest bucket number with observed activity. using Range = std::pair; // The observed activity for a single bucket kind. - struct Activity + class Activity { + public: Buckets buckets; Range range{std::numeric_limits::max(), 0}; + + Activity() = default; + bool hasActivity() const + { + return !buckets.empty(); + } }; public: CActivity(CHotspotEventVisitor& _container, __uint64 _id) @@ -62,11 +69,13 @@ class CHotspotEventVisitor : public CInterfaceOf void forEachBucket(IBucketVisitor& visitor) { const char* path = container.operation.queryMetaInfoState().queryFilePath(id); + if (!hasActivity()) // suppress inactive files + return; visitor.arrive(id, path); for (unsigned kind = 0; kind < NumNodeKinds; kind++) { Activity& act = activity[kind]; - if (act.range.first != std::numeric_limits::max() && !act.buckets.empty()) + if (act.hasActivity()) { for (bucket_type bucket = act.range.first; bucket <= act.range.second; bucket++) { @@ -102,6 +111,16 @@ class CHotspotEventVisitor : public CInterfaceOf return 0; } + bool hasActivity() const + { + for (const Activity& act : activity) + { + if (act.hasActivity()) + return true; + } + return false; + } + private: CHotspotEventVisitor& container; // back reference to obtain shared configuration __uint64 id{0}; diff --git a/common/eventconsumption/eventindexsummarize.cpp b/common/eventconsumption/eventindexsummarize.cpp index b5c9c27f677..228b6ee4312 100644 --- a/common/eventconsumption/eventindexsummarize.cpp +++ b/common/eventconsumption/eventindexsummarize.cpp @@ -665,6 +665,11 @@ class CTraceCollector : public CSummaryCollector public: // IEventVisitor virtual bool visitEvent(CEvent& event) override { + // Allow EventQueryStart events to pass through; trace ID to service name + // mapping is built earlier by the metadata parser (CMetaInfoState::visitEvent) + if (event.queryType() == EventQueryStart) + return true; + // Implicit event filter applied unconditionally if (queryEventContext(event.queryType()) != EventCtxIndex) return true; @@ -688,7 +693,7 @@ class CTraceCollector : public CSummaryCollector virtual void summarize() override { // Determine which node kinds have data - bool haveNodeKindEntries[NumNodeKinds] = {false,}; + std::fill_n(haveNodeKindEntries, NumNodeKinds, false); for (Cache::value_type& entry : stats) { TraceStats& traceStats = entry.second; @@ -701,23 +706,18 @@ class CTraceCollector : public CSummaryCollector } } } + if (summarization == IndexSummarization::byService) + summarizeByService(); + else + summarizeByTrace(); + } +protected: + void summarizeByTrace() + { StringBuffer line; appendCSVColumns(line, "Trace ID", "Service Name", "First Timestamp", "Last Timestamp", "Unique Files"); - - // Add aggregate statistics headers - appendNodeKindHeaders(line, "Total "); - - // Add node kind specific headers only for kinds that have data - for (unsigned nodeKind = 0; nodeKind < NumNodeKinds; nodeKind++) - { - if (!haveNodeKindEntries[nodeKind]) - continue; - const char* nodeKindName = mapNodeKind((NodeKind)nodeKind); - VStringBuffer prefix("%c%s ", toupper(*nodeKindName), nodeKindName + 1); - appendNodeKindHeaders(line, prefix); - } - + appendNodeKindHeaders(line); outputLine(line); for (Cache::value_type& entry : stats) @@ -749,7 +749,6 @@ class CTraceCollector : public CSummaryCollector // Create aggregate statistics across all node kinds NodeKindStats aggregateStats = {}; - std::unordered_map allNodeMemory; for (unsigned nodeKind = 0; nodeKind < NumNodeKinds; nodeKind++) aggregateStats.addStats(traceStats.kinds[nodeKind]); @@ -770,7 +769,115 @@ class CTraceCollector : public CSummaryCollector } } + void summarizeByService() + { + // Extended TraceStats with trace counter for service summarization + class ServiceStats : public TraceStats + { + public: + uint32_t traceCount{0}; // Count of traces represented in this service + NodeKindStats totals; + + ServiceStats() = default; + void addStats(const TraceStats& other) + { + for (unsigned nodeKind = 0; nodeKind < NumNodeKinds; nodeKind++) + { + const NodeKindStats& nodeKindStats = other.kinds[nodeKind]; + kinds[nodeKind].addStats(nodeKindStats); + totals.addStats(nodeKindStats); + } + } + }; + + // Aggregate trace stats by service name + std::unordered_map serviceStats; + + for (Cache::value_type& entry : stats) + { + const TraceHashKey& traceKey = entry.first; + TraceStats& traceStats = entry.second; + + // Find service name for this trace ID, or use empty string if not found + const char* serviceName = operation.queryMetaInfoState().queryServiceName(traceKey.traceId.str()); + if (!serviceName) + serviceName = ""; + ServiceStats& serviceAggregateStats = serviceStats[serviceName]; + + // Aggregate the stats + serviceAggregateStats.addStats(traceStats); + + // Increment trace count + serviceAggregateStats.traceCount++; + + // Merge unique files + serviceAggregateStats.uniqueFileIds.insert(traceStats.uniqueFileIds.begin(), traceStats.uniqueFileIds.end()); + + // Update timestamp ranges + if (traceStats.firstTimestamp != UINT64_MAX) + serviceAggregateStats.firstTimestamp = std::min(serviceAggregateStats.firstTimestamp, traceStats.firstTimestamp); + if (traceStats.lastTimestamp > 0) + serviceAggregateStats.lastTimestamp = std::max(serviceAggregateStats.lastTimestamp, traceStats.lastTimestamp); + } + + // Output aggregated service stats + StringBuffer line; + appendCSVColumns(line, "Service Name", "Trace Count", "First Timestamp", "Last Timestamp", "Unique Files"); + appendNodeKindHeaders(line); + outputLine(line); + + for (auto& serviceEntry : serviceStats) + { + const std::string& serviceName = serviceEntry.first; + ServiceStats& serviceStatsEntry = serviceEntry.second; + + // Format timestamps using CDateTime (empty if no valid timestamps were found) + StringBuffer firstTsStr, lastTsStr; + if (serviceStatsEntry.firstTimestamp != UINT64_MAX) + { + CDateTime firstDt; + firstDt.setTimeStampNs(serviceStatsEntry.firstTimestamp); + firstDt.getString(firstTsStr); + } + if (serviceStatsEntry.lastTimestamp > 0) + { + CDateTime lastDt; + lastDt.setTimeStampNs(serviceStatsEntry.lastTimestamp); + lastDt.getString(lastTsStr); + } + + const char* displayServiceName = serviceName.empty() ? "" : serviceName.c_str(); + appendCSVColumns(line, displayServiceName, serviceStatsEntry.traceCount, firstTsStr.str(), lastTsStr.str(), serviceStatsEntry.uniqueFileIds.size()); + appendNodeKindData(line, serviceStatsEntry.totals); + for (unsigned nodeKind = 0; nodeKind < NumNodeKinds; nodeKind++) + { + if (!haveNodeKindEntries[nodeKind]) + continue; + const NodeKindStats& nodeStats = serviceStatsEntry.kinds[nodeKind]; + appendNodeKindData(line, nodeStats); + } + outputLine(line); + } + } + protected: + + void appendNodeKindHeaders(StringBuffer& line) + { + // Add aggregate statistics headers + appendNodeKindHeaders(line, "Total "); + + // Add node kind specific headers only for kinds that have data + for (unsigned nodeKind = 0; nodeKind < NumNodeKinds; nodeKind++) + { + if (!haveNodeKindEntries[nodeKind]) + continue; + const char* nodeKindName = mapNodeKind((NodeKind)nodeKind); + VStringBuffer prefix("%c%s ", toupper(*nodeKindName), nodeKindName + 1); + appendNodeKindHeaders(line, prefix); + } + } + void appendNodeKindHeaders(StringBuffer& line, const char* prefix) { appendCSVEventsHeaders(line, prefix); @@ -807,6 +914,8 @@ class CTraceCollector : public CSummaryCollector protected: using Cache = std::unordered_map; Cache stats; + bool haveNodeKindEntries[NumNodeKinds] = {false,}; + }; bool CIndexFileSummary::doOp() @@ -820,6 +929,7 @@ bool CIndexFileSummary::doOp() collector.setown(new CNodeCollector(*this, summarization, out)); break; case IndexSummarization::byTrace: + case IndexSummarization::byService: collector.setown(new CTraceCollector(*this, summarization, out)); break; default: diff --git a/common/eventconsumption/eventindexsummarize.h b/common/eventconsumption/eventindexsummarize.h index d2f6bf1125d..dc00f8546f8 100644 --- a/common/eventconsumption/eventindexsummarize.h +++ b/common/eventconsumption/eventindexsummarize.h @@ -30,6 +30,7 @@ enum class IndexSummarization byNodeKind, byNode, byTrace, + byService, }; class event_decl CIndexFileSummary : public CEventConsumingOp diff --git a/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOJSON.xml b/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOJSON.xml index 419513f74d8..8dd6dd2b6e5 100644 --- a/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOJSON.xml +++ b/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOJSON.xml @@ -4,16 +4,16 @@ TOJSON - TOJSON + TOJSON( record + [,ALL]) TOJSON TOJSON function - ( record ) + - + @@ -22,6 +22,15 @@ The row (record) of data to convert to JSON format. + + ALL + + Specifies fields with empty strings are included in the + output. Without the ALL flag, TOJSON omits fields that contain only + whitespace or are empty after trimming. + + Return: diff --git a/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOXML.xml b/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOXML.xml index b64dc10020d..8891fa0f358 100644 --- a/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOXML.xml +++ b/docs/EN_US/ECLLanguageReference/ECLR_mods/BltInFunc-TOXML.xml @@ -4,16 +4,16 @@ TOXML - TOXML + TOXML( record + [,ALL]) TOXML TOXML function - ( record ) + - + @@ -23,6 +23,15 @@ format. + + ALL + + Specifies fields with empty strings are included in the + output. Without the ALL flag, TOXML omits fields that contain only + whitespace or are empty after trimming. + + Return: @@ -32,8 +41,6 @@ - - The TOXML function returns a single UTF-8 string with the data in the record re-formatted as XML. If the RECORD structure of the record has diff --git a/docs/common/Version.xml b/docs/common/Version.xml index 88b53c282c8..4669df9d130 100644 --- a/docs/common/Version.xml +++ b/docs/common/Version.xml @@ -5,11 +5,11 @@ DEVELOPER NON-GENERATED VERSION - © 2025 HPCC + © 2026 HPCC Systems®. All rights reserved - 2025 HPCC Systems®. All rights + 2026 HPCC Systems®. All rights reserved @@ -23,9 +23,9 @@ serve one purpose and that is to store the chapterinfo and other information used by several document components. - 2025 Version ${DOC_VERSION} + 2026 Version ${DOC_VERSION} - 2025 + 2026 The following line is the code to be put into the document you wish to include the above version info in: diff --git a/docs/common/Version.xml.in b/docs/common/Version.xml.in index 030b68e470a..b7e04204969 100644 --- a/docs/common/Version.xml.in +++ b/docs/common/Version.xml.in @@ -3,13 +3,13 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> - 2025 Version ${DOC_VERSION} + 2026 Version ${DOC_VERSION} - © 2025 HPCC + © 2026 HPCC Systems®. All rights reserved - 2025 HPCC Systems®. All rights + 2026 HPCC Systems®. All rights reserved @@ -24,9 +24,9 @@ serve one purpose and that is to store the chapterinfo the above sections that are being used by several other documents. - 2025 Version ${DOC_VERSION} + 2026 Version ${DOC_VERSION} - 2025 + 2026 The following line is the code to be put into the document you wish to include the above version info in: diff --git a/ecl/hql/hqlgram.y b/ecl/hql/hqlgram.y index 0ce3db013cf..741d769f55a 100644 --- a/ecl/hql/hqlgram.y +++ b/ecl/hql/hqlgram.y @@ -6454,15 +6454,15 @@ primexpr1 parser->reportError(ERR_NEGATIVE_WIDTH, $5, "REALFORMAT does not support negative widths"); $$.setExpr(createValue(no_realformat, makeStringType(UNKNOWN_LENGTH, NULL, NULL), $3.getExpr(), $5.getExpr(), $7.getExpr())); } - | TOXML '(' dataRow ')' + | TOXML '(' dataRow optToXMLToJSONFlags ')' { //MORE Could allow ,NOTRIM,OPT,???flags - $$.setExpr(createValue(no_toxml, makeUtf8Type(UNKNOWN_LENGTH, NULL), $3.getExpr())); + $$.setExpr(createValue(no_toxml, makeUtf8Type(UNKNOWN_LENGTH, NULL), $3.getExpr(), $4.getExpr())); } - | TOJSON '(' dataRow ')' + | TOJSON '(' dataRow optToXMLToJSONFlags ')' { //MORE Could allow ,NOTRIM,OPT,???flags - $$.setExpr(createValue(no_tojson, makeUtf8Type(UNKNOWN_LENGTH, NULL), $3.getExpr())); + $$.setExpr(createValue(no_tojson, makeUtf8Type(UNKNOWN_LENGTH, NULL), $3.getExpr(), $4.getExpr())); } | REGEXFIND '(' expression ',' expression regexOpt ')' { @@ -7449,6 +7449,11 @@ xmlEncodeFlags | ',' ALL { $$.setExpr(createAttribute(allAtom)); } ; +optToXMLToJSONFlags + : { $$.setNullExpr(); } + | ',' ALL { $$.setExpr(createAttribute(allAtom)); } + ; + aggregateFlags : { $$.setNullExpr(); } | aggregateFlags ',' aggregateFlag diff --git a/ecl/hqlcpp/hqlcpp.cpp b/ecl/hqlcpp/hqlcpp.cpp index 70b659ed96a..1fdd999d769 100644 --- a/ecl/hqlcpp/hqlcpp.cpp +++ b/ecl/hqlcpp/hqlcpp.cpp @@ -8133,11 +8133,15 @@ void HqlCppTranslator::doBuildAssignFormat(IIdAtom * func, BuildCtx & ctx, const void HqlCppTranslator::doBuildAssignToXmlorJson(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr) { IHqlExpression * row = expr->queryChild(0); + int flags = XWFtrim|XWFopt|XWFnoindent; + + if (expr->hasAttribute(allAtom)) + flags &= ~XWFopt; HqlExprArray args; args.append(*buildMetaParameter(row)); args.append(*LINK(row)); - args.append(*getSizetConstant(XWFtrim|XWFopt|XWFnoindent)); + args.append(*getSizetConstant(flags)); node_operator op = expr->getOperator(); OwnedHqlExpr call = bindFunctionCall((op==no_tojson) ? ctxGetRowJsonId : ctxGetRowXmlId, args); buildExprAssign(ctx, target, call); diff --git a/esp/src/package-lock.json b/esp/src/package-lock.json index 94ab4ca46f3..0bc008bc216 100644 --- a/esp/src/package-lock.json +++ b/esp/src/package-lock.json @@ -30,7 +30,7 @@ "@hpcc-js/map": "3.2.15", "@hpcc-js/other": "3.2.10", "@hpcc-js/phosphor": "3.2.10", - "@hpcc-js/timeline": "3.2.2", + "@hpcc-js/timeline": "3.3.0", "@hpcc-js/util": "3.3.9", "@hpcc-js/wasm-duckdb": "1.9.0", "@hpcc-js/wasm-graphviz": "1.11.0", @@ -2365,21 +2365,21 @@ "license": "BSD-3-Clause" }, "node_modules/@hpcc-js/api": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/api/-/api-3.4.2.tgz", - "integrity": "sha512-++xtgIhdEOnvKfAOt+SP9t2YOXGNwbLNhf1F+ghw36XSylKmzyYAY3Lgg9Q2weB/hUNgv4bqZZgDxE9d8QpONw==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/@hpcc-js/api/-/api-3.4.5.tgz", + "integrity": "sha512-DPtXTJKEH6+jhTsM7tesnVHc02SUQPp3+PHwiHoFNMW+OgzknVTuvge2+JPuKdDugGgIcfNPths6dDbesZY50Q==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^3.5.2" + "@hpcc-js/common": "^3.6.1" } }, "node_modules/@hpcc-js/api/node_modules/@hpcc-js/common": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.5.2.tgz", - "integrity": "sha512-bhcmae3SmMVWaLOI24Zi7jhw8Hqwjdnp3EvtjpBOLar6UcZl4IPgrpw4XP47HH7UPJ2hqM7HlecrtJiUv/4nSw==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.6.1.tgz", + "integrity": "sha512-7QyaqVIvFhLfR1ivB1HpZtAISGY3dC6StbJ40glOOdxSo43V2/9FLN8KgsbUsvkRTeqlMsS0hCQ8MlG+Ko7ERQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/util": "^3.4.2", + "@hpcc-js/util": "^3.4.4", "@types/d3-array": "1.2.12", "@types/d3-brush": "1.1.8", "@types/d3-collection": "1.0.13", @@ -2398,9 +2398,9 @@ } }, "node_modules/@hpcc-js/api/node_modules/@hpcc-js/util": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.2.tgz", - "integrity": "sha512-u/9zz5i0y/NrBi5z56XLDxPL4BEtrCjZpkcGu0GmsCjlSRa+McvUo9NndQQgmdTRdcagkAKoabz87iVDrVrPQg==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.4.tgz", + "integrity": "sha512-FEhjiWusFUexqQ1klQ5bTLgoNACXi3s16hYjq9sd0V5g94lvtfRPGRKRrrsY51NmVtFg39KO4rr53U3HR1SS5g==", "license": "Apache-2.0", "dependencies": { "@xmldom/xmldom": "0.9.8" @@ -2513,13 +2513,13 @@ "license": "Apache-2.0" }, "node_modules/@hpcc-js/dgrid": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid/-/dgrid-3.5.2.tgz", - "integrity": "sha512-4hm1AMvj0Rt3/7zo2qvkXujfmn1FGAXnWk6MUlqPJwdRqrlfo99BTMj8bCKCvFEysCpmsRBu3aFBWvdXzoVx6Q==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid/-/dgrid-3.5.5.tgz", + "integrity": "sha512-D5jT7Id+IJjMwrHkMOkOCEuGM4FRUUvjsNHDWVbKKxRXifGpYbHErJHgiGCD6vQLk3AUeJqoZDotoZwjyVdHsQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^3.5.2", - "@hpcc-js/util": "^3.4.2" + "@hpcc-js/common": "^3.6.1", + "@hpcc-js/util": "^3.4.4" }, "peerDependencies": { "@hpcc-js/dgrid-shim": "^3.1.0" @@ -2533,12 +2533,12 @@ "peer": true }, "node_modules/@hpcc-js/dgrid/node_modules/@hpcc-js/common": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.5.2.tgz", - "integrity": "sha512-bhcmae3SmMVWaLOI24Zi7jhw8Hqwjdnp3EvtjpBOLar6UcZl4IPgrpw4XP47HH7UPJ2hqM7HlecrtJiUv/4nSw==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.6.1.tgz", + "integrity": "sha512-7QyaqVIvFhLfR1ivB1HpZtAISGY3dC6StbJ40glOOdxSo43V2/9FLN8KgsbUsvkRTeqlMsS0hCQ8MlG+Ko7ERQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/util": "^3.4.2", + "@hpcc-js/util": "^3.4.4", "@types/d3-array": "1.2.12", "@types/d3-brush": "1.1.8", "@types/d3-collection": "1.0.13", @@ -2557,9 +2557,9 @@ } }, "node_modules/@hpcc-js/dgrid/node_modules/@hpcc-js/util": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.2.tgz", - "integrity": "sha512-u/9zz5i0y/NrBi5z56XLDxPL4BEtrCjZpkcGu0GmsCjlSRa+McvUo9NndQQgmdTRdcagkAKoabz87iVDrVrPQg==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.4.tgz", + "integrity": "sha512-FEhjiWusFUexqQ1klQ5bTLgoNACXi3s16hYjq9sd0V5g94lvtfRPGRKRrrsY51NmVtFg39KO4rr53U3HR1SS5g==", "license": "Apache-2.0", "dependencies": { "@xmldom/xmldom": "0.9.8" @@ -2765,21 +2765,21 @@ } }, "node_modules/@hpcc-js/react": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/react/-/react-3.4.2.tgz", - "integrity": "sha512-N4ecrnswjXCkfeQ1KLzYvH35bfjHbqBoEinIzc2ba5WzUUnIxm2nAUp1OtFYxw0qrYpW2L8mL6brUBfjdiancg==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/@hpcc-js/react/-/react-3.4.5.tgz", + "integrity": "sha512-Y3B37YxdsJWyrYb0AAaZ5VpJD3YKKeF1DwDT2297YnxdKin1eopCvrMmkrWayw9BD3jvDHO0+nk6PqyVsfHSYQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^3.5.2" + "@hpcc-js/common": "^3.6.1" } }, "node_modules/@hpcc-js/react/node_modules/@hpcc-js/common": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.5.2.tgz", - "integrity": "sha512-bhcmae3SmMVWaLOI24Zi7jhw8Hqwjdnp3EvtjpBOLar6UcZl4IPgrpw4XP47HH7UPJ2hqM7HlecrtJiUv/4nSw==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.6.1.tgz", + "integrity": "sha512-7QyaqVIvFhLfR1ivB1HpZtAISGY3dC6StbJ40glOOdxSo43V2/9FLN8KgsbUsvkRTeqlMsS0hCQ8MlG+Ko7ERQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/util": "^3.4.2", + "@hpcc-js/util": "^3.4.4", "@types/d3-array": "1.2.12", "@types/d3-brush": "1.1.8", "@types/d3-collection": "1.0.13", @@ -2798,35 +2798,46 @@ } }, "node_modules/@hpcc-js/react/node_modules/@hpcc-js/util": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.2.tgz", - "integrity": "sha512-u/9zz5i0y/NrBi5z56XLDxPL4BEtrCjZpkcGu0GmsCjlSRa+McvUo9NndQQgmdTRdcagkAKoabz87iVDrVrPQg==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.4.tgz", + "integrity": "sha512-FEhjiWusFUexqQ1klQ5bTLgoNACXi3s16hYjq9sd0V5g94lvtfRPGRKRrrsY51NmVtFg39KO4rr53U3HR1SS5g==", "license": "Apache-2.0", "dependencies": { "@xmldom/xmldom": "0.9.8" } }, "node_modules/@hpcc-js/timeline": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/timeline/-/timeline-3.2.2.tgz", - "integrity": "sha512-aJBDEnaYbNohhLkcQ2yt4FP3d7F5FVc5kN04L7W0AHgG31FKCZGFpz+004LWrCnjUzvzKfeWmBpklgsZbNXi2A==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/timeline/-/timeline-3.3.0.tgz", + "integrity": "sha512-ZhrT7O2JbttgAfY9kaQLtppLX1CY737lHghWA9lzcpZzyO7x9/QdIIFWYgR+kg1Un2NrRcA2y35K+BFaT/7SVA==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^3.4.2", - "@hpcc-js/chart": "^3.5.2", - "@hpcc-js/common": "^3.5.2", - "@hpcc-js/html": "^3.3.2", - "@hpcc-js/layout": "^3.4.2", - "@hpcc-js/react": "^3.4.2" + "@hpcc-js/api": "^3.4.5", + "@hpcc-js/chart": "^3.6.1", + "@hpcc-js/common": "^3.6.1", + "@hpcc-js/html": "^3.3.5", + "@hpcc-js/layout": "^3.4.5", + "@hpcc-js/react": "^3.4.5" + } + }, + "node_modules/@hpcc-js/timeline/node_modules/@hpcc-js/chart": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/chart/-/chart-3.6.1.tgz", + "integrity": "sha512-rv0oasg9eg0mUB14HdLVmPgxZ0w7Xjb+Q0D/PglGBWaJX4t3DLUeWt6hopgJjHKkV3WGZX2njxHJK6tPsUrEpA==", + "license": "Apache-2.0", + "dependencies": { + "@hpcc-js/api": "^3.4.5", + "@hpcc-js/common": "^3.6.1", + "@hpcc-js/util": "^3.4.4" } }, "node_modules/@hpcc-js/timeline/node_modules/@hpcc-js/common": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.5.2.tgz", - "integrity": "sha512-bhcmae3SmMVWaLOI24Zi7jhw8Hqwjdnp3EvtjpBOLar6UcZl4IPgrpw4XP47HH7UPJ2hqM7HlecrtJiUv/4nSw==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-3.6.1.tgz", + "integrity": "sha512-7QyaqVIvFhLfR1ivB1HpZtAISGY3dC6StbJ40glOOdxSo43V2/9FLN8KgsbUsvkRTeqlMsS0hCQ8MlG+Ko7ERQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/util": "^3.4.2", + "@hpcc-js/util": "^3.4.4", "@types/d3-array": "1.2.12", "@types/d3-brush": "1.1.8", "@types/d3-collection": "1.0.13", @@ -2845,33 +2856,33 @@ } }, "node_modules/@hpcc-js/timeline/node_modules/@hpcc-js/html": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/html/-/html-3.3.2.tgz", - "integrity": "sha512-OLAbWrZnnKR2Q3zrqshDdgdCxy9E3ennyGBaGO+cUn3uzhH1zEOuZ4BnICdn/r82T8xr6w6B/YiYi6xFY13pJQ==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@hpcc-js/html/-/html-3.3.5.tgz", + "integrity": "sha512-I3jtk9LU20Rd7gg9U4/ZiyOf/bSiW+1eirnPn9saitboMGOq1jV5xmkuJogbnU7zQcIfxUWrSRXVCISLmwRvCQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^3.5.2", - "@hpcc-js/react": "^3.4.2", - "@hpcc-js/util": "^3.4.2" + "@hpcc-js/common": "^3.6.1", + "@hpcc-js/react": "^3.4.5", + "@hpcc-js/util": "^3.4.4" } }, "node_modules/@hpcc-js/timeline/node_modules/@hpcc-js/layout": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/layout/-/layout-3.4.2.tgz", - "integrity": "sha512-jm8CCUdMZUht5iTpNYJyzWr5xezW0o7MPQjPvgJbdZt24Z2q/5ta15u+vw4Clqx/v8qBUgrIn468ecSoDv1DYg==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/@hpcc-js/layout/-/layout-3.4.5.tgz", + "integrity": "sha512-ZECjBMM088XY783E1zBLX8PJ9YzIGhzcNyxug2zvg0m0y8NAU/9oV/fGswv+9ORfxlBCk143QhcwwqSglQZXcQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^3.4.2", - "@hpcc-js/chart": "^3.5.2", - "@hpcc-js/common": "^3.5.2", - "@hpcc-js/dgrid": "^3.5.2", - "@hpcc-js/util": "^3.4.2" + "@hpcc-js/api": "^3.4.5", + "@hpcc-js/chart": "^3.6.1", + "@hpcc-js/common": "^3.6.1", + "@hpcc-js/dgrid": "^3.5.5", + "@hpcc-js/util": "^3.4.4" } }, "node_modules/@hpcc-js/timeline/node_modules/@hpcc-js/util": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.2.tgz", - "integrity": "sha512-u/9zz5i0y/NrBi5z56XLDxPL4BEtrCjZpkcGu0GmsCjlSRa+McvUo9NndQQgmdTRdcagkAKoabz87iVDrVrPQg==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-3.4.4.tgz", + "integrity": "sha512-FEhjiWusFUexqQ1klQ5bTLgoNACXi3s16hYjq9sd0V5g94lvtfRPGRKRrrsY51NmVtFg39KO4rr53U3HR1SS5g==", "license": "Apache-2.0", "dependencies": { "@xmldom/xmldom": "0.9.8" diff --git a/esp/src/package.json b/esp/src/package.json index e8b8fd434d6..0c763bda096 100644 --- a/esp/src/package.json +++ b/esp/src/package.json @@ -61,7 +61,7 @@ "@hpcc-js/map": "3.2.15", "@hpcc-js/other": "3.2.10", "@hpcc-js/phosphor": "3.2.10", - "@hpcc-js/timeline": "3.2.2", + "@hpcc-js/timeline": "3.3.0", "@hpcc-js/util": "3.3.9", "@hpcc-js/wasm-duckdb": "1.9.0", "@hpcc-js/wasm-graphviz": "1.11.0", diff --git a/esp/src/src/Timings.ts b/esp/src/src/Timings.ts index 3aa90c8894e..88c6b874675 100644 --- a/esp/src/src/Timings.ts +++ b/esp/src/src/Timings.ts @@ -33,6 +33,7 @@ export class WUTimelinePatched extends WUTimeline { this._gantt .bucketHeight(22) .gutter(4) + .preserveZoom(true) .overlapTolerence(-100) .oddSeriesBackground("transparent") .evenSeriesBackground("transparent") diff --git a/testing/regress/ecl/key/tojson_all.xml b/testing/regress/ecl/key/tojson_all.xml new file mode 100644 index 00000000000..e650e306772 --- /dev/null +++ b/testing/regress/ecl/key/tojson_all.xml @@ -0,0 +1,12 @@ + + PASSED + + + PASSED + + + PASSED + + + PASSED + diff --git a/testing/regress/ecl/key/toxml_all.xml b/testing/regress/ecl/key/toxml_all.xml new file mode 100644 index 00000000000..e650e306772 --- /dev/null +++ b/testing/regress/ecl/key/toxml_all.xml @@ -0,0 +1,12 @@ + + PASSED + + + PASSED + + + PASSED + + + PASSED + diff --git a/testing/regress/ecl/tojson_all.ecl b/testing/regress/ecl/tojson_all.ecl new file mode 100644 index 00000000000..426ebbc4b9d --- /dev/null +++ b/testing/regress/ecl/tojson_all.ecl @@ -0,0 +1,34 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2026 HPCC Systems®. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +############################################################################## */ + +// HPCC-23274 + +LAYOUT := RECORD + UNSIGNED1 person_id; + STRING first_name; + STRING last_name; +END; + +ds := DATASET([{1, 'Jane', 'Doe'}, {2, '', 'Doe'}], LAYOUT); + +// Without ALL flag +OUTPUT(IF(TOJSON(ds[1]) = u8'"person_id": 1, "first_name": "Jane", "last_name": "Doe"', 'PASSED', 'FAILED'), NAMED('result_1')); +OUTPUT(IF(TOJSON(ds[2]) = u8'"person_id": 2, "last_name": "Doe"', 'PASSED', 'FAILED'), NAMED('result_2')); + +// With ALL flag +OUTPUT(IF(TOJSON(ds[1], ALL) = u8'"person_id": 1, "first_name": "Jane", "last_name": "Doe"', 'PASSED', 'FAILED'), NAMED('result_3')); +OUTPUT(IF(TOJSON(ds[2], ALL) = u8'"person_id": 2, "first_name": "", "last_name": "Doe"', 'PASSED', 'FAILED'), NAMED('result_4')); diff --git a/testing/regress/ecl/toxml_all.ecl b/testing/regress/ecl/toxml_all.ecl new file mode 100644 index 00000000000..32d153d10a5 --- /dev/null +++ b/testing/regress/ecl/toxml_all.ecl @@ -0,0 +1,34 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2026 HPCC Systems®. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +############################################################################## */ + +// HPCC-23274 + +LAYOUT := RECORD + UNSIGNED1 person_id; + STRING first_name; + STRING last_name; +END; + +ds := DATASET([{1, 'Jane', 'Doe'}, {2, '', 'Doe'}], LAYOUT); + +// Without ALL flag +OUTPUT(IF(TOXML(ds[1]) = u8'1JaneDoe', 'PASSED', 'FAILED'), NAMED('result_1')); +OUTPUT(IF(TOXML(ds[2]) = u8'2Doe', 'PASSED', 'FAILED'), NAMED('result_2')); + +// With ALL flag +OUTPUT(IF(TOXML(ds[1], ALL) = u8'1JaneDoe', 'PASSED', 'FAILED'), NAMED('result_3')); +OUTPUT(IF(TOXML(ds[2], ALL) = u8'2Doe', 'PASSED', 'FAILED'), NAMED('result_4')); diff --git a/tools/evtool/evtindex_summary.cpp b/tools/evtool/evtindex_summary.cpp index 805d0b028c2..45cb9b084f7 100644 --- a/tools/evtool/evtindex_summary.cpp +++ b/tools/evtool/evtindex_summary.cpp @@ -42,6 +42,9 @@ class CEvtIndexSummaryCommand : public TEventConsumingCommand case 't': op.setSummarization(IndexSummarization::byTrace); break; + case 's': + op.setSummarization(IndexSummarization::byService); + break; default: return false; } @@ -52,8 +55,8 @@ class CEvtIndexSummaryCommand : public TEventConsumingCommand { return R"!!!(Summarize the index events in a binary event file. Activity can be aggregate by either index file ID, node kind, individual node (as identified by file -ID and file offset), or trace ID. One line of output is produced for each -event group. +ID and file offset), trace ID, or service name. One line of output is produced +for each event group. )!!!"; } @@ -76,6 +79,7 @@ R"!!!( -f Summarize activity by file. -k Summarize activity by node kind. -n Summarize activity by node. -t Summarize activity by trace ID. + -s Summarize activity by service name. )!!!"; size32_t usageStrLength = size32_t(strlen(usageStr)); out.put(usageStrLength, usageStr);