fix: 客户端日志打印变更配置名称,修复 Node.js Dockerfile 和 ConfigList 页面布局
- 各客户端 deleted/changed 日志增加具体配置名称输出 - Node.js Dockerfile 改为单阶段构建,修复依赖找不到问题 - ConfigList.vue 查询条件拆分为独立卡片,新增查询/重置按钮 - Node.js 客户端日志统一使用 console.error
This commit is contained in:
+6
-21
@@ -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"]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
+1
-1
@@ -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);
|
||||||
|
|||||||
@@ -1,15 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card>
|
<div>
|
||||||
<div slot="header" style="display: flex; justify-content: space-between; align-items: center">
|
<el-card style="margin-bottom: 16px">
|
||||||
<span>配置列表</span>
|
<el-form :inline="true" @submit.native.prevent="handleSearch">
|
||||||
<div>
|
<el-form-item label="环境">
|
||||||
<el-select v-model="query.env" placeholder="环境" clearable style="width: 160px; margin-right: 10px" @change="loadData">
|
<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>
|
||||||
<el-table-column prop="env" label="环境" width="80"></el-table-column>
|
<el-table-column prop="env" label="环境" width="80"></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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user