This is an automated email from the ASF dual-hosted git repository.
zqr10159 pushed a commit to branch 2.0.0
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/2.0.0 by this push:
new 6756e4a071 Add operation filters to log trace handoffs
6756e4a071 is described below
commit 6756e4a071569df799f154389aa1283285d07ba7
Author: Logic <[email protected]>
AuthorDate: Wed Jun 10 09:18:10 2026 +0800
Add operation filters to log trace handoffs
---
web-next/lib/log-manage/view-model.test.ts | 31 ++++++++++++++++++++++++++++++
web-next/lib/log-manage/view-model.ts | 19 ++++++++++++++++++
2 files changed, 50 insertions(+)
diff --git a/web-next/lib/log-manage/view-model.test.ts
b/web-next/lib/log-manage/view-model.test.ts
index 1f9651a3f1..cb08703f3d 100644
--- a/web-next/lib/log-manage/view-model.test.ts
+++ b/web-next/lib/log-manage/view-model.test.ts
@@ -745,6 +745,7 @@ describe('log view model', () => {
const traceParams = new URL(result.traceHref,
'https://example.com').searchParams;
expect(traceParams.get('operationName')).toBe('POST /checkout');
+ expect(traceParams.get('attributeFilter')).toBeNull();
const metricsParams = new URL(result.metricsHref,
'https://example.com').searchParams;
expect(metricsParams.get('operationName')).toBe('POST /checkout');
@@ -761,6 +762,36 @@ describe('log view model', () => {
expect(alertRuleParams.get('operationName')).toBe('POST /checkout');
});
+ it('adds an executable trace attribute filter for operation-level log
handoffs', () => {
+ const result = buildLogHandoffLinks(
+ {
+ traceId: '',
+ spanId: '',
+ timeUnixNano: 1_710_000_000_000_000_000,
+ resource: {
+ 'service.name': 'checkout',
+ 'service.namespace': 'payments'
+ },
+ attributes: {
+ 'http.route': '/checkout/:id'
+ }
+ } as any,
+ {
+ entityId: '7',
+ entityType: 'service',
+ entityName: 'Checkout API'
+ }
+ );
+
+ const traceParams = new URL(result.traceHref,
'https://example.com').searchParams;
+ expect(traceParams.get('traceId')).toBeNull();
+ expect(traceParams.get('spanId')).toBeNull();
+ expect(traceParams.get('serviceName')).toBe('checkout');
+ expect(traceParams.get('serviceNamespace')).toBe('payments');
+ expect(traceParams.get('operationName')).toBe('/checkout/:id');
+
expect(traceParams.get('attributeFilter')).toBe('http.route="/checkout/:id"');
+ });
+
it('can override trace and metrics return paths with the current log
workspace route', () => {
const currentLogReturnTo =
`/log/manage?traceId=trace-1&spanId=span-1&view=stream&start=1709999100000&end=1710000060000&returnTo=%2Foverview&returnLabel=${encodeURIComponent(t('menu.log.manage'))}`;
diff --git a/web-next/lib/log-manage/view-model.ts
b/web-next/lib/log-manage/view-model.ts
index ef2536804f..6aa4a872e4 100644
--- a/web-next/lib/log-manage/view-model.ts
+++ b/web-next/lib/log-manage/view-model.ts
@@ -340,6 +340,23 @@ function buildMetricFilterExpression(name: string, value:
string | undefined) {
return `${trimmedName}="${escapeMetricFilterValue(trimmedValue)}"`;
}
+function buildTraceAttributeFilterExpression(name: string, value: string |
undefined) {
+ const trimmedName = name.trim();
+ const trimmedValue = value?.trim();
+ if (!/^[A-Za-z0-9_.:-]+$/.test(trimmedName) || !trimmedValue || trimmedValue
=== '-') return undefined;
+ return `${trimmedName}="${escapeMetricFilterValue(trimmedValue)}"`;
+}
+
+function buildLogTraceOperationAttributeFilter(selectedLog: LogEntry | null,
traceId: string | undefined, spanId: string | undefined) {
+ if (traceId || spanId) return undefined;
+ const httpRoute = firstText(
+ readAttribute(selectedLog?.attributes, 'http.route'),
+ readAttribute(selectedLog?.attributes, 'http_route')
+ );
+ if (httpRoute) return buildTraceAttributeFilterExpression('http.route',
httpRoute);
+ return buildTraceAttributeFilterExpression('span.name',
readAttribute(selectedLog?.attributes, 'span.name'));
+}
+
function buildLogMetricsResourceFilter(selectedLog: LogEntry | null) {
const expressions = [
buildMetricFilterExpression('k8s.namespace.name', firstText(
@@ -750,6 +767,8 @@ export function buildLogHandoffLinks(
if (spanId) traceParams.set('spanId', spanId);
if (traceContext.serviceName) traceParams.set('serviceName',
traceContext.serviceName);
appendSignalRouteContext(traceParams, traceContext);
+ const traceOperationAttributeFilter =
buildLogTraceOperationAttributeFilter(selectedLog, traceId, spanId);
+ if (traceOperationAttributeFilter) traceParams.set('attributeFilter',
traceOperationAttributeFilter);
const traceHref = traceParams.toString() ?
`/trace/manage?${traceParams.toString()}` : '/trace/manage';
const metricsParams = new URLSearchParams();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]