mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-11 03:06:54 +00:00
fix(mesh): log boot state to console so docker logs surfaces mesh status (#1159)
MeshService records its boot summary and setup failures only through logActivity (in-memory ring buffer + WS listeners), which the Routing tab consumes. The docker-logs surface was silent for the mesh subsystem, so operators running Sencho-in-Docker had no boot-time visibility into whether the data plane came up cleanly. Mirror the existing logActivity entries to console without replacing them: - MeshService.start() success summary: console.log / console.warn / console.error gated on the summary level. Format: [Mesh] data plane ok, self attached at <ip>, subnet <X> [Mesh] data plane unavailable (<reason>: <message>) - recordSetupFailure: console.warn for the expected dev-mode not_in_docker case, console.error for real failures. Format: [Mesh] data plane unavailable (<reason>, subnet <X>): <sanitized> The activity entries that already drive the Routing tab banner stay intact; the console lines are purely additive for the docker logs workflow. Two new unit tests assert the failure and not_in_docker console mirrors fire with the [Mesh] prefix. Fixes F-5.
This commit is contained in:
@@ -441,3 +441,43 @@ describe('MeshService.setupMeshNetwork subnet auto-fallback', () => {
|
||||
expect(status.reason).toBe('subnet_mismatch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('MeshService console.log mirror (F-5)', () => {
|
||||
it('mirrors a setup failure to console.error with the [Mesh] prefix', async () => {
|
||||
process.env.SENCHO_MESH_SUBNET = '10.42.0.0/24';
|
||||
process.env.HOSTNAME = 'sencho';
|
||||
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mockDocker({
|
||||
createNetwork: vi.fn().mockRejectedValue(
|
||||
Object.assign(new Error('Pool overlaps with other one on this address space'), { statusCode: 500 }),
|
||||
),
|
||||
});
|
||||
|
||||
const svc = MeshService.getInstance();
|
||||
await callSetup(svc);
|
||||
|
||||
const meshLines = errSpy.mock.calls
|
||||
.map((args) => String(args[0]))
|
||||
.filter((line) => line.startsWith('[Mesh] data plane unavailable'));
|
||||
expect(meshLines.length).toBeGreaterThan(0);
|
||||
expect(meshLines[0]).toContain('subnet_overlap');
|
||||
expect(meshLines[0]).toContain('10.42.0.0/24');
|
||||
expect(meshLines[0]).toMatch(/overlap/i);
|
||||
});
|
||||
|
||||
it('mirrors a not_in_docker condition to console.warn (expected dev-mode case)', async () => {
|
||||
process.env.SENCHO_MESH_SUBNET = '10.42.0.0/24';
|
||||
delete process.env.HOSTNAME;
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
mockDocker();
|
||||
|
||||
const svc = MeshService.getInstance();
|
||||
await callSetup(svc);
|
||||
|
||||
const meshLines = warnSpy.mock.calls
|
||||
.map((args) => String(args[0]))
|
||||
.filter((line) => line.startsWith('[Mesh] data plane unavailable'));
|
||||
expect(meshLines.length).toBeGreaterThan(0);
|
||||
expect(meshLines[0]).toContain('not_in_docker');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user