fix: 客户端日志打印变更配置名称,修复 Node.js Dockerfile 和 ConfigList 页面布局

- 各客户端 deleted/changed 日志增加具体配置名称输出
- Node.js Dockerfile 改为单阶段构建,修复依赖找不到问题
- ConfigList.vue 查询条件拆分为独立卡片,新增查询/重置按钮
- Node.js 客户端日志统一使用 console.error
This commit is contained in:
2026-06-22 21:14:27 +08:00
parent b513435723
commit ec33f8c52a
7 changed files with 50 additions and 42 deletions
+6 -21
View File
@@ -1,27 +1,12 @@
# Build stage
FROM node:18-alpine AS build
WORKDIR /src
# Copy client library
COPY kenaito-conf-nodejs-client/ ./kenaito-conf-nodejs-client/
# Copy demo project
COPY kenaito-conf-nodejs-client-demo/ ./kenaito-conf-nodejs-client-demo/
# Install client locally, then demo dependencies
WORKDIR /src/kenaito-conf-nodejs-client
RUN npm link
WORKDIR /src/kenaito-conf-nodejs-client-demo
RUN npm link kenaito-conf && npm install
# Runtime stage
FROM node:18-alpine FROM node:18-alpine
WORKDIR /app WORKDIR /app
COPY --from=build /src/kenaito-conf-nodejs-client-demo .
COPY kenaito-conf-nodejs-client/ ./kenaito-conf-nodejs-client/
COPY kenaito-conf-nodejs-client-demo/ ./kenaito-conf-nodejs-client-demo/
WORKDIR /app/kenaito-conf-nodejs-client-demo
RUN npm install ../kenaito-conf-nodejs-client && npm install
EXPOSE 8083 EXPOSE 8083
CMD ["node", "app.js"] CMD ["node", "app.js"]
+6 -2
View File
@@ -231,7 +231,7 @@ func (c *Client) fetchChanged() error {
delete(c.configs, key) delete(c.configs, key)
} }
c.mu.Unlock() c.mu.Unlock()
log.Printf("[ConfigClient] %d configs deleted", len(deletedKeys)) log.Printf("[ConfigClient] %d configs deleted: %s", len(deletedKeys), strings.Join(deletedKeys, ", "))
delete(wrapper.Data, "deletedKeys") delete(wrapper.Data, "deletedKeys")
} }
@@ -250,7 +250,11 @@ func (c *Client) fetchChanged() error {
// notify listeners // notify listeners
c.listener.Notify(changed) c.listener.Notify(changed)
log.Printf("[ConfigClient] %d configs changed", len(changed)) changedKeys := make([]string, 0, len(changed))
for k := range changed {
changedKeys = append(changedKeys, k)
}
log.Printf("[ConfigClient] %d configs changed: %s", len(changed), strings.Join(changedKeys, ", "))
} }
return nil return nil
+3 -3
View File
@@ -15,7 +15,7 @@ function onConfigChanged(changed) {
for (const [k, v] of Object.entries(changed)) { for (const [k, v] of Object.entries(changed)) {
if (k in configValues) { if (k in configValues) {
configValues[k] = v; configValues[k] = v;
console.log(`config updated: ${k} = ${v}`); console.error(`config updated: ${k} = ${v}`);
} }
} }
} }
@@ -57,13 +57,13 @@ async function main() {
configValues[k] = remote[k]; configValues[k] = remote[k];
} }
} }
console.info(`loaded ${Object.keys(remote).length} configs from remote`); console.error(`loaded ${Object.keys(remote).length} configs from remote`);
} catch (err) { } catch (err) {
console.error('failed to init config client, using local defaults:', err); console.error('failed to init config client, using local defaults:', err);
} }
app.listen(port, '0.0.0.0', () => { app.listen(port, '0.0.0.0', () => {
console.info(`server started on port ${port}`); console.error(`server started on port ${port}`);
}); });
} }
+4 -4
View File
@@ -38,7 +38,7 @@ export class ConfigClient {
const cached = this.cache.read(); const cached = this.cache.read();
if (cached) { if (cached) {
this.applyConfigs(cached); this.applyConfigs(cached);
console.info('[ConfigClient] loaded', Object.keys(this.configs).length, 'configs from cache'); console.error('[ConfigClient] loaded', Object.keys(this.configs).length, 'configs from cache');
} else { } else {
throw new Error(`fetch configs failed and no cache: ${err.message}`); throw new Error(`fetch configs failed and no cache: ${err.message}`);
} }
@@ -90,7 +90,7 @@ export class ConfigClient {
this.cache.write(data); this.cache.write(data);
this.applyConfigs(data); this.applyConfigs(data);
console.info('[ConfigClient] fetched', Object.keys(this.configs).length, 'configs'); console.error('[ConfigClient] fetched', Object.keys(this.configs).length, 'configs');
} }
async fetchChanged() { async fetchChanged() {
@@ -134,7 +134,7 @@ export class ConfigClient {
for (const key of deletedKeys) { for (const key of deletedKeys) {
delete this.configs[key]; delete this.configs[key];
} }
console.info('[ConfigClient]', deletedKeys.length, 'configs deleted'); console.error('[ConfigClient]', deletedKeys.length, 'configs deleted:', deletedKeys.join(', '));
delete changedData['deletedKeys']; delete changedData['deletedKeys'];
} }
@@ -145,7 +145,7 @@ export class ConfigClient {
Object.assign(this.configs, changed); Object.assign(this.configs, changed);
this.listener.notify(changed); this.listener.notify(changed);
console.info('[ConfigClient]', Object.keys(changed).length, 'configs changed'); console.error('[ConfigClient]', Object.keys(changed).length, 'configs changed:', Object.keys(changed).join(', '));
} }
applyConfigs(data) { applyConfigs(data) {
@@ -110,7 +110,7 @@ class ConfigClient:
with self._lock: with self._lock:
for key in deleted_keys: for key in deleted_keys:
self._configs.pop(key, None) self._configs.pop(key, None)
logger.info("[ConfigClient] %d configs deleted", len(deleted_keys)) logger.info("[ConfigClient] %d configs deleted: %s", len(deleted_keys), ", ".join(deleted_keys))
if changed_data: if changed_data:
changed = {} changed = {}
@@ -121,7 +121,7 @@ class ConfigClient:
self._configs.update(changed) self._configs.update(changed)
self._listener.notify(changed) self._listener.notify(changed)
logger.info("[ConfigClient] %d configs changed", len(changed)) logger.info("[ConfigClient] %d configs changed: %s", len(changed), ", ".join(changed.keys()))
def _apply_configs(self, data: dict) -> None: def _apply_configs(self, data: dict) -> None:
with self._lock: with self._lock:
@@ -69,7 +69,7 @@ public class InternalConfigChangeListener {
if (deletedKeysStr != null && !deletedKeysStr.isEmpty()) { if (deletedKeysStr != null && !deletedKeysStr.isEmpty()) {
String[] deletedKeys = deletedKeysStr.split(","); String[] deletedKeys = deletedKeysStr.split(",");
context.removeConfigs(java.util.Arrays.asList(deletedKeys)); context.removeConfigs(java.util.Arrays.asList(deletedKeys));
logger.info("[ConfigClient] {} configs deleted", deletedKeys.length); logger.info("[ConfigClient] {} configs deleted: {}", deletedKeys.length, String.join(", ", deletedKeys));
} }
} }
if (!data.isEmpty()) context.updateConfig(data); if (!data.isEmpty()) context.updateConfig(data);
+24 -5
View File
@@ -1,14 +1,23 @@
<template> <template>
<el-card>
<div slot="header" style="display: flex; justify-content: space-between; align-items: center">
<span>配置列表</span>
<div> <div>
<el-select v-model="query.env" placeholder="环境" clearable style="width: 160px; margin-right: 10px" @change="loadData"> <el-card style="margin-bottom: 16px">
<el-form :inline="true" @submit.native.prevent="handleSearch">
<el-form-item label="环境">
<el-select v-model="query.env" placeholder="请选择" clearable style="width: 160px">
<el-option v-for="p in profiles" :key="p.value" :label="p.label" :value="p.value"></el-option> <el-option v-for="p in profiles" :key="p.value" :label="p.label" :value="p.value"></el-option>
</el-select> </el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card>
<div slot="header" style="display: flex; justify-content: flex-end">
<el-button type="primary" @click="$router.push('/config/add')">新建配置</el-button> <el-button type="primary" @click="$router.push('/config/add')">新建配置</el-button>
</div> </div>
</div>
<el-table :data="list" v-loading="loading" border stripe> <el-table :data="list" v-loading="loading" border stripe>
<el-table-column prop="id" label="ID" width="60"></el-table-column> <el-table-column prop="id" label="ID" width="60"></el-table-column>
<el-table-column prop="name" label="配置名"></el-table-column> <el-table-column prop="name" label="配置名"></el-table-column>
@@ -115,6 +124,7 @@
</el-table> </el-table>
</el-dialog> </el-dialog>
</el-card> </el-card>
</div>
</template> </template>
<script> <script>
@@ -236,6 +246,15 @@ export default {
this.loadProfiles() this.loadProfiles()
}, },
methods: { methods: {
handleSearch() {
this.query.pageNo = 1
this.loadData()
},
handleReset() {
this.query.env = ''
this.query.pageNo = 1
this.loadData()
},
async loadData() { async loadData() {
this.loading = true this.loading = true
try { try {