feature: Implement Event stream for Application/Instance/Service #1472#1487
feature: Implement Event stream for Application/Instance/Service #1472#1487ambiguous-pointer wants to merge 3 commits into
Conversation
|
Please fix the CI problem @ambiguous-pointer |
71cc134 to
769173b
Compare
|
Apologies for the formatting oversight. I have run the linter locally, fixed the Vue component styles, and force-pushed the updates. The CI check is now green. |
There was a problem hiding this comment.
Pull request overview
This PR adds an end-to-end “event timeline” feature across the backend and ui-vue3, ingesting Kubernetes Event objects and recording registry-side (ZooKeeper/Nacos) platform events, then exposing unified, time-sorted, paginated timelines for Applications / Instances / Services with frontend visualization.
Changes:
- Introduces new resource kinds (
K8sEvent,PlatformEvent) with store indexes, plus K8s lister-watcher ingestion and registry subscriber-side PlatformEvent recording. - Adds Console API endpoints (
/application/event,/instance/event,/service/event) that merge and paginate K8s + Platform events. - Adds a reusable Vue timeline component and wires event tabs + routes + i18n + mocks to display the unified event stream.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| ui-vue3/src/views/resources/services/tabs/event.vue | Replaces placeholder timeline with EventTimeline + paginated API loading for service events |
| ui-vue3/src/views/resources/instances/tabs/event.vue | Adds EventTimeline-based instance event tab with pagination |
| ui-vue3/src/views/resources/instances/tabs/detail.vue | Adds “instance missing/offline” empty state and silences detail fetch errors |
| ui-vue3/src/views/resources/instances/slots/InstanceTabHeaderSlot.vue | Silences errors when fetching instance lifecycle state |
| ui-vue3/src/views/resources/applications/tabs/event.vue | Replaces old custom timeline UI with shared EventTimeline + pagination |
| ui-vue3/src/types/api.ts | Adds EventItem type for unified timeline entries |
| ui-vue3/src/router/defaultRoutes.ts | Enables event tabs in routes for application/instance/service |
| ui-vue3/src/mocks/handlers/service.ts | Adds mock /service/event response |
| ui-vue3/src/mocks/handlers/instance.ts | Adds mock /instance/event response |
| ui-vue3/src/mocks/handlers/app.ts | Updates mock application events to unified EventItem format with totals |
| ui-vue3/src/components/EventTimeline.vue | New shared timeline component with infinite-scroll loading |
| ui-vue3/src/base/i18n/zh.ts | Adds eventExpiryHint translation |
| ui-vue3/src/base/i18n/en.ts | Adds eventExpiryHint translation |
| ui-vue3/src/base/http/request.ts | Adds silentError support for suppressing toast/log output |
| ui-vue3/src/api/service/service.ts | Adds listServiceEvent() client |
| ui-vue3/src/api/service/instance.ts | Adds silentError option for getInstanceDetail() and adds listInstanceEvent() |
| ui-vue3/src/api/service/app.ts | Tightens listApplicationEvent() params typing (adds pagination params) |
| pkg/engine/kubernetes/listerwatcher/k8s_event.go | New watcher to list/watch core/v1 Events and transform into K8sEvent resources |
| pkg/engine/kubernetes/factory.go | Registers the new K8sEvent lister-watcher in the K8s engine |
| pkg/core/store/index/platform_event.go | Adds store indexes for PlatformEvent queries |
| pkg/core/store/index/k8s_event.go | Adds store indexes for K8sEvent queries |
| pkg/core/resource/apis/mesh/v1alpha1/platformevent_types.go | Defines PlatformEvent resource schema + list |
| pkg/core/resource/apis/mesh/v1alpha1/k8sevent_types.go | Defines K8sEvent resource schema + list |
| pkg/core/events/component.go | Downgrades “no subscriber” log from INFO to DEBUG |
| pkg/core/discovery/subscriber/zk_metadata.go | Records PlatformEvent entries for ZK metadata add/update |
| pkg/core/discovery/subscriber/zk_config.go | Records PlatformEvent entries for ZK config add/update/delete |
| pkg/core/discovery/subscriber/platform_event_recorder.go | Adds shared PlatformEvent store-write utility |
| pkg/core/discovery/subscriber/nacos_service.go | Records PlatformEvent entries for Nacos instance/consumer metadata changes |
| pkg/console/service/event.go | Implements merged K8s + Platform event querying and pagination |
| pkg/console/router/router.go | Adds /application/event, /instance/event, /service/event routes |
| pkg/console/model/event.go | Adds request/response models for event queries |
| pkg/console/handler/event.go | Adds handlers for the new event endpoints |
| api/mesh/v1alpha1/k8s_event.proto | Adds proto definition for K8sEvent spec |
| api/mesh/v1alpha1/k8s_event.go | Adds Go struct + Clone for K8sEvent spec |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| res, ok := items[i].(*K8sEventResource) | ||
| if !ok { | ||
| logger.Errorf("unexpected resource type, expected: %s, get %s", K8sEventKind, res.ResourceKind()) | ||
| continue | ||
| } |
| watch( | ||
| () => [props.hasMore, props.loading, props.loadingMore, props.events.length], | ||
| () => { | ||
| tryLoadMore() | ||
| } | ||
| ) |
| total := len(entries) | ||
| start := pageReq.PageOffset | ||
| if start > total { | ||
| start = total | ||
| } | ||
| end := start + pageReq.PageSize | ||
| if pageReq.PageSize <= 0 || end > total { | ||
| end = total | ||
| } |
| mesh := constants.DefaultMesh | ||
| res := meshresource.NewK8sEventResourceWithAttributes(k8sEvent.Namespace+"/"+k8sEvent.Name, mesh) | ||
| res.Spec = &meshproto.K8sEvent{ | ||
| Namespace: k8sEvent.Namespace, | ||
| Reason: k8sEvent.Reason, | ||
| Message: k8sEvent.Message, | ||
| Type: k8sEvent.Type, | ||
| InvolvedObjKind: k8sEvent.InvolvedObject.Kind, | ||
| InvolvedObjName: k8sEvent.InvolvedObject.Name, | ||
| SourceComponent: k8sEvent.Source.Component, | ||
| SourceHost: k8sEvent.Source.Host, | ||
| FirstTimestamp: k8sEvent.FirstTimestamp.Format(constants.TimeFormatStr), | ||
| LastTimestamp: k8sEvent.LastTimestamp.Format(constants.TimeFormatStr), | ||
| Count: k8sEvent.Count, | ||
| EventSource: "KUBERNETES", | ||
| } |
| func ListInstanceEvents(ctx consolectx.Context, req *model.EventQueryReq) (*model.EventListResp, error) { | ||
| k8sEvents, err := manager.ListByIndexes[*meshresource.K8sEventResource]( | ||
| ctx.ResourceManager(), | ||
| meshresource.K8sEventKind, | ||
| []index.IndexCondition{ | ||
| {IndexName: index.ByMeshIndex, Value: req.Mesh, Operator: index.Equals}, | ||
| }, | ||
| ) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| platformEvents, err := manager.ListByIndexes[*meshresource.PlatformEventResource]( | ||
| ctx.ResourceManager(), | ||
| meshresource.PlatformEventKind, | ||
| []index.IndexCondition{ | ||
| {IndexName: index.ByMeshIndex, Value: req.Mesh, Operator: index.Equals}, | ||
| }, | ||
| ) | ||
| if err != nil { | ||
| return nil, err | ||
| } |
robocanic
left a comment
There was a problem hiding this comment.
Great Work! Thanks a lot for your PR! I've reviewed the PR generally and the whole structrue is totally fine. There are some issues both I and Qoder found, please check the review and find them if make sense.
completeness-review.md
correctness-review.md
impact-review.md
|
|
||
| import "api/mesh/options.proto"; | ||
|
|
||
| message K8sEvent { |
There was a problem hiding this comment.
Question: PlatformEvent为什么没有proto定义?
| } | ||
|
|
||
| func buildApplicationK8sConditions(req *model.EventQueryReq) []index.IndexCondition { | ||
| conditions := []index.IndexCondition{ |
There was a problem hiding this comment.
Correction: 这里的AppName参数需要前端必传,不传需要抛异常,不然这里的过滤条件太宽泛了,会把整个mesh的所有事件全部捞出来。下面的过滤条件也是一样
769173b to
5144582
Compare
…ent ingestion ([apache#1472](apache#1472)) - Add K8sEvent resource type (proto + Go spec) and store indexes - Add K8sEventListerWatcher to watch K8s /api/v1/events via client-go - Register K8sEventListerWatcher in Kubernetes EngineFactory - Add /application/event, /instance/event, /service/event console API endpoints - Add EventTimeline shared Vue component with normal/warning node styles - Wire up event tabs for application, instance, and service detail pages - Un-hide event tab routes in frontend router - Add mock event handlers for development - Add PlatformEvent resource type (platformevent_types.go) with store indexes - Add shared platform_event_recorder utility for event recording - Record ZK config change events (tag-route, condition-route, dynamic-config) - Record ZK metadata events (provider/consumer metadata added/updated) - Record Nacos instance registration/deregistration events - Record Nacos consumer metadata change events - Merge K8s events and Platform events into unified timeline in event query service - Downgrade "no subscriber" log level from INFO to DEBUG to reduce log noise
|
@ambiguous-pointer please merge the develop and resolve the conflicts. |
…, watch spam, silent drops, delete-before-add - K8sEventListerWatcher: check IsZero() before formatting FirstTimestamp/LastTimestamp to avoid emitting synthetic "0001-01-01 00:00:00" values that break timeline ordering. - EventTimeline.vue: remove unconditional watch() that triggered cascading loadMore calls; rely solely on IntersectionObserver for scroll-based pagination. - RecordRegistryEvent: log a warning when dropping events due to empty Mesh or Message instead of silently discarding them. - K8sEventSubscriber.writeEvent: delete the informer-written (original-key) entry only after a successful Add of the timestamp-prefixed entry, preventing permanent event loss when Add fails.
5144582 to
31ba4e7
Compare
|
@robocanic Conflicts resolved after merging develop. The build is now passing and all checks are green. Please review. |
概述本 PR 为 Dubbo 应用、实例和服务引入了统一的事件时间线功能,将 Kubernetes 原生事件和注册中心侧生命周期事件(ZooKeeper / Nacos)统一摄入到 架构设计统一事件模型所有事件——无论是来自 K8s 还是注册中心——都以
message K8sEvent {
string namespace = 1; // K8s 命名空间(注册中心事件为空)
string reason = 2; // K8s reason 或注册中心 action
string message = 3; // 可读描述
string type = 4; // "Normal" | "Warning"
string involvedObjKind = 5; // K8s: "Pod" | 注册中心: "registry" | "config" | "metadata"
string involvedObjName = 6; // K8s: Pod 名 | 注册中心: 层级编码(见下文)
string sourceComponent = 7; // K8s: source component | 注册中心: "zookeeper" | "nacos"
string sourceHost = 8; // K8s: source host | 注册中心: 实例 IP
string firstTimestamp = 9;
string lastTimestamp = 10;
int32 count = 11;
string eventSource = 12; // "KUBERNETES" | "REGISTRY"
}数据流核心设计决策1. 统一
|
| 事件类别 | InvolvedObjName | 示例 |
|---|---|---|
| 实例(注册中心) | {appName}/{ip} |
test-event/10.244.1.89 |
| 配置(ZK) | {appName}/{serviceName} |
test-event/com.example.TestService |
| 元数据(ZK) | {appName}/{serviceName} |
test-event/com.example.TestService |
K8s 事件直接使用 Pod 名作为 InvolvedObjName(如 test-event-app-7cd9897566-xlxpf)。
Console API 的 HasPrefix 查询可以用单一索引条件匹配两种编码风格。
3. 时间戳前缀 Key 实现时序排序
PageListByIndexes 按资源 Key 的字母序排列。为实现时间序,prefixTimestampKey() 在 Key 前追加降序纳秒时间戳:
key = "{MAX_INT64 - timestampNano}_{namespace}/{podName}"
越新的事件前缀越小 → 排序越靠前。注册中心事件在 RecordRegistryEvent() 中已包含纳秒时间戳。
4. K8s 事件的 Mesh 对齐
K8s Event 对象没有"Dubbo mesh"的概念。K8sEventListerWatcher 以 engine ID 作为初始 mesh,随后 K8sEventSubscriber.alignMeshFromRuntimeInstance() 通过 Pod 名跨所有 mesh 查找对应的 RuntimeInstance(使用 ByRuntimeInstanceNameIndex 索引),将事件 mesh 对齐为正确的 discovery mesh。
5. K8s 事件过滤(仅 Pod、仅 Dubbo)
- Field Selector:
involvedObject.kind=Pod— 在 K8s API 层面过滤,避免集群级噪声(Node 事件、Namespace 事件等)。 - DubboAppIdentifier:在
K8sEventSubscriber中,通过配置的DubboAppIdentifier(如按 labelapp匹配)丢弃非 Dubbo Pod 的事件,不进入存储。
文件清单
API 层
| 文件 | 说明 |
|---|---|
api/mesh/v1alpha1/k8s_event.proto |
统一 K8sEvent 消息的 proto 定义 |
api/mesh/v1alpha1/k8s_event.go |
手写 Go 类型,含 Clone() 方法 |
核心资源类型与索引
| 文件 | 说明 |
|---|---|
pkg/core/resource/apis/mesh/v1alpha1/k8sevent_types.go |
K8sEventResource + K8sEventResourceList 类型定义,含 DeepCopy、SetItems 等 |
pkg/core/store/index/k8s_event.go |
四个索引:ByK8sEventInvolvedObjKind、ByK8sEventInvolvedObjName、ByK8sEventType、ByK8sEventSource |
pkg/core/store/index/runtime_instance.go |
新增 ByRuntimeInstanceNameIndex 索引,支持跨 mesh 按 Pod 名查找 RuntimeInstance |
K8s Engine
| 文件 | 说明 |
|---|---|
pkg/engine/kubernetes/factory.go |
在已有 PodListerWatcher 旁注册 K8sEventListerWatcher |
pkg/engine/kubernetes/listerwatcher/k8s_event.go |
K8sEventListerWatcher — List+Watch api/v1/events(仅 Pod),TransformFunc 含零值时间戳保护,转换为 K8sEventResource |
Discovery 订阅器
| 文件 | 说明 |
|---|---|
pkg/core/discovery/subscriber/k8s_event.go |
K8sEventSubscriber — 按 DubboAppIdentifier + Pod kind 过滤 K8s 事件,从 RuntimeInstance 对齐 mesh,为 Key 添加时间戳前缀。REGISTRY 事件直接透传。含原地修复:delete 移至 Add 成功后执行,防止数据丢失。 |
pkg/core/discovery/subscriber/registry_event_adapter.go |
RecordRegistryEvent() — 共享工具函数,创建 EventSource="REGISTRY" 的 K8sEventResource,编码层级化 InvolvedObjName。Mesh 或 Message 为空时 Warn 日志而非静默丢弃。 |
pkg/core/discovery/subscriber/zk_config.go |
ZKConfigEventSubscriber — 记录 tag-route / condition-route / dynamic-config 的增删改事件 |
pkg/core/discovery/subscriber/zk_metadata.go |
ZKMetadataEventSubscriber — 记录 provider/consumer 元数据的增改事件 |
pkg/core/discovery/subscriber/nacos_service.go |
NacosServiceEventSubscriber — 记录实例注册/注销/更新及 consumer 元数据增删改事件 |
pkg/core/discovery/component.go |
将 K8sEventSubscriber 接入 discovery 生命周期(仅当 engine 类型为 Kubernetes 时) |
Console API
| 文件 | 说明 |
|---|---|
pkg/console/service/event.go |
核心查询逻辑:ListApplicationEvents、ListInstanceEvents、ListServiceEvents。分别从 RuntimeInstance 解析 Pod 名 → 查询 K8sEvent 存储 → 按 involved object name 过滤 → 分页返回。负数 offset 和零 pageSize 已安全处理。 |
pkg/console/handler/event.go |
HTTP 处理器:GetApplicationEvents、GetInstanceEvents、GetServiceEvents |
pkg/console/model/event.go |
请求/响应类型:EventQueryReq、EventItem、EventListResp |
pkg/console/router/router.go |
路由注册:GET /instance/event、GET /application/event、GET /service/event |
前端
| 文件 | 说明 |
|---|---|
ui-vue3/src/components/EventTimeline.vue |
可复用时间线组件,基于 Ant Design a-timeline,左右交替布局,normal/warning 图标区分,IntersectionObserver 驱动无限滚动(已移除 watch 无条件触发 loadMore) |
ui-vue3/src/views/resources/applications/tabs/event.vue |
应用事件 Tab — 接入 EventTimeline,传入 appName + mesh |
ui-vue3/src/views/resources/instances/tabs/event.vue |
实例事件 Tab — 接入 EventTimeline,传入 instanceName + ip + appName + mesh |
ui-vue3/src/views/resources/services/tabs/event.vue |
服务事件 Tab — 接入 EventTimeline,传入 serviceName + appName + mesh |
ui-vue3/src/api/service/app.ts |
listApplicationEvent() API 函数 |
ui-vue3/src/api/service/instance.ts |
listInstanceEvent() API 函数 |
ui-vue3/src/api/service/service.ts |
listServiceEvent() API 函数 |
ui-vue3/src/types/api.ts |
EventItem TypeScript 类型定义 |
ui-vue3/src/router/defaultRoutes.ts |
恢复之前被注释的事件 Tab 路由 |
配置与小幅改动
| 文件 | 说明 |
|---|---|
pkg/core/events/component.go |
"no subscriber for resource" 日志级别从 INFO 降为 DEBUG,减少 K8sEvent 和 Service 类型(有意不设订阅器)的日志噪音 |
API 参考
GET /api/v1/application/event
查询参数:
| 参数 | 必填 | 说明 |
|---|---|---|
mesh |
是 | Dubbo mesh 名称 |
appName |
是 | 应用名称 |
pageOffset |
否 | 分页偏移量(默认 0,负值自动修正为 0) |
pageSize |
否 | 每页条数(默认 20) |
GET /api/v1/instance/event
| 参数 | 必填 | 说明 |
|---|---|---|
mesh |
是 | Dubbo mesh 名称 |
ip |
是 | 实例 IP 地址 |
instanceName |
否 | 实例名称(作为额外匹配候选项) |
appName |
否 | 应用名称(用于匹配注册中心事件) |
pageOffset |
否 | 分页偏移量 |
pageSize |
否 | 每页条数 |
GET /api/v1/service/event
| 参数 | 必填 | 说明 |
|---|---|---|
mesh |
是 | Dubbo mesh 名称 |
serviceName |
是 | 服务名称 |
appName |
是 | 应用名称 |
pageOffset |
否 | 分页偏移量 |
pageSize |
否 | 每页条数 |
EventItem 响应格式
{
"time": "2026-07-26 15:40:54",
"type": "normal",
"message": "Started container agnhost",
"source": "kubelet"
}E2E 验证
在 3 节点集群上测试:
| 场景 | 结果 |
|---|---|
应用事件(mesh=dubbo-samples-shop,appName=test-event) |
返回 96 条 |
实例事件(mesh=dubbo-samples-shop,ip=10.244.1.93) |
每个 Pod 返回 4 条 |
| 时间线排序 | 按时间倒序排列 ✓ |
| source 标签(kubelet、default-scheduler) | 正确渲染 ✓ |
| Warning 事件 | 黄色图标 + 橙色标签 ✓ |
| 空状态 | "暂无事件" 占位提示 ✓ |
| 无限滚动 | IntersectionObserver 驱动 loadMore ✓ |
|
既然Event包括了K8s侧的和registry侧的,感觉是不是换个统一的名字更好? |
K8sEvent was originally named for K8s-sourced events only, but now also carries registry-side events (ZK/Nacos) via the EventSource discriminator. Rename to LifecycleEvent to accurately reflect its role as a unified lifecycle event type covering both K8s and registry origins. - Proto: K8sEvent → LifecycleEvent - Resource: K8sEventResource → LifecycleEventResource - Kind: K8sEventKind → LifecycleEventKind - Subscriber: K8sEventSubscriber → LifecycleEventSubscriber - Index constants: ByK8sEvent* → ByLifecycleEvent* - Files: k8s_event.* → lifecycle_event.* - Retained: K8sEventListerWatcher (K8s-specific component)
|
|
@robocanic 已经安装要求修改了 |



This change introduces a complete event timeline feature for applications, instances, and services
based on discussion #1474 and
issue #1472.
It ingests Kubernetes events via the cluster API and records platform events from ZooKeeper
and Nacos registration centers, merging them into a unified, time-sorted timeline with full
frontend visualization.
📌 What's New
Kubernetes Event Ingestion
K8sEvent resource type
K8sEventResourcewith protoK8sEventspec (api/mesh/v1alpha1/k8s_event.proto+Go generated code). Captures namespace, reason, message, type, involved object kind/name,
source component/host, first/last timestamps, count, and a static
EventSource: "KUBERNETES"marker.K8sEventListerWatcher
New
K8sEventListerWatcher(pkg/engine/kubernetes/listerwatcher/k8s_event.go) watchesapi/v1/eventsacross all namespaces usingclient-go'sListWatch+TransformFunc.Registered in the K8s
EngineFactoryalongside the existingPodListerWatcher.K8sEvent store indexes (
pkg/core/store/index/k8s_event.go)ByK8sEventInvolvedObjKind,ByK8sEventInvolvedObjName,ByK8sEventType,ByK8sEventSource— enables efficient queries by mesh, involved object, event type, and source.
Platform Event Recording (ZooKeeper & Nacos)
PlatformEvent resource type
PlatformEventResourcewithPlatformEventspec (pkg/core/resource/apis/mesh/v1alpha1/platformevent_types.go).Carries
AppName,InstanceName,InstanceIP,ServiceName,Type(normal/warning),Message,Source(Zookeeper/Nacos),SourceType(provider/consumer/config),Category,Action, andEventTime.Shared platform event recorder (
pkg/core/discovery/subscriber/platform_event_recorder.go)recordPlatformEvent()utility that createsPlatformEventResourceinstances and persiststhem directly to the store via
storeRouter.ResourceKindRoute(PlatformEventKind).ZooKeeper config change events
ZKConfigEventSubscriber(pkg/core/discovery/subscriber/zk_config.go) recordstag-route,condition-route, anddynamic-configadded/updated/deleted eventsvia
recordConfigPlatformEvent().ZooKeeper metadata change events
ZKMetadataEventSubscriber(pkg/core/discovery/subscriber/zk_metadata.go) recordsprovider and consumer metadata added/updated events via
recordMetadataPlatformEvent().Nacos instance registration/deregistration events
NacosServiceEventSubscriber(pkg/core/discovery/subscriber/nacos_service.go)records
Nacos instance registered,deregistered, andupdatedevents withapplication name, IP, and port via
recordNacosInstanceEvents().Nacos consumer metadata change events
Same subscriber records
Nacos consumer metadata added/updatedeventsvia
recordNacosConsumerEvents().PlatformEvent store indexes (
pkg/core/store/index/platform_event.go)ByPlatformEventAppName,ByPlatformEventInstanceName,ByPlatformEventInstanceIP,ByPlatformEventServiceName,ByPlatformEventSourceType— enables per-entity event queries.Unified Event Timeline Query Service
pkg/console/service/event.go)GET /application/eventGET /instance/eventGET /service/eventEach endpoint queries both
K8sEventandPlatformEventstores in parallel,merges results, sorts by time descending, and returns paginated unified timeline entries.
{ "code": "Success", "message": "success", "data": { "list": [ { "time": "2026-06-07 17:39:14", "type": "warning", "message": "Error updating Endpoint Slices...", "source": "endpoint-slice-controller" }, { "time": "2026-06-07 10:25:04", "type": "normal", "message": "Zookeeper provider metadata added: demo-app → com.example.TestService", "source": "Zookeeper" }, { "time": "2026-06-07 10:25:05", "type": "normal", "message": "Nacos instance registered: shop-order 10.244.1.29:20882", "source": "Nacos" } ], "total": 78 } }Frontend Event Timeline Visualization
EventTimeline shared component (
ui-vue3/src/components/EventTimeline.vue)Reusable Vue component with alternating left/right timeline layout using Ant Design.
Each event node displays: timestamp, icon (check-circle for normal, warning for warnings),
message text, and source tag. Supports infinite scroll with "load more" pagination.
Degraded/expired events show an empty state with "过期事件不会存储" (expired events
are not stored) watermark.
Application event tab (
ui-vue3/src/views/resources/applications/tabs/event.vue)Wires the EventTimeline component into the application detail page as an "事件" tab.
Queries events filtered by
appNameand currentmesh.Instance event tab (
ui-vue3/src/views/resources/instances/tabs/event.vue)Wires the EventTimeline component into the instance detail page as an "事件" tab.
Queries events filtered by
instanceNameandinstanceIP.Service event tab (
ui-vue3/src/views/resources/services/tabs/event.vue)Wires the EventTimeline component into the service detail page as an "事件" tab.
Queries events filtered by
serviceName.Event tab restored in routes (
ui-vue3/src/router/defaultRoutes.ts)Event tab routes previously commented out are now enabled for all three resource types.
Minor Improvements
pkg/core/events/component.go)"no subscriber for resource" message downgraded from
INFOtoDEBUGto reducelog noise (991 occurrences per 5 minutes for
K8sEventandService).📁 Affected Areas / Review Checklist
api/mesh/v1alpha1/k8s_event.go,k8s_event.protopkg/console/service/event.go,handler/event.go,model/event.go,router/router.gopkg/core/events/component.gopkg/core/resource/apis/mesh/v1alpha1/k8sevent_types.go,platformevent_types.gopkg/core/store/index/k8s_event.go,platform_event.gopkg/core/discovery/subscriber/nacos_service.go,zk_config.go,zk_metadata.gopkg/core/discovery/subscriber/platform_event_recorder.gopkg/engine/kubernetes/factory.go,listerwatcher/k8s_event.goui-vue3/src/components/EventTimeline.vueui-vue3/src/views/resources/{applications,instances,services}/tabs/event.vueui-vue3/src/api/service/{app,instance,service}.tsui-vue3/src/router/defaultRoutes.tsui-vue3/src/types/api.ts🔄 Data Flow Architecture
🧪 E2E Verification
Tested against a 6-node kind cluster (
cluster-ha-new, k8s v1.35.1) with:🔮 Known Limitations
K8s events use mesh "default" — K8s events are not associated with any discovery
mesh. The frontend registry selector must be set to "default" (or unset) to view
K8s events. There is a UX gap: the registry dropdown does not show "default" as an
explicit option.
No event TTL / cleanup — Events accumulate indefinitely in the store. There is
no retention policy, TTL, or automatic cleanup mechanism for any store backend.
No subscriber for K8sEvent and Service — K8sEvent and Service resources are
stored but no event subscriber processes them (by design — they only need storage).
The EventBus emits a "no subscriber" debug log for these kinds.
PlatformEvent bypasses EventBus — PlatformEvents are created as side-effects
within subscriber
ProcessEventmethods and stored directly viaeventStore.Add(), bypassing the EventBus entirely. This means PlatformEventsthemselves cannot be observed by downstream subscribers.