log de saida
This commit is contained in:
@@ -81,9 +81,42 @@ Campos **nullable** permitem limpar o valor escolhendo "Limpar campo (null)" ou
|
|||||||
|
|
||||||
O app também tenta carregar `../clarizen-lib/.env` se não houver `.env` local.
|
O app também tenta carregar `../clarizen-lib/.env` se não houver `.env` local.
|
||||||
|
|
||||||
|
## Log de execução
|
||||||
|
|
||||||
|
Após cada atualização concluída, o app gera `run-log-<timestamp>.json` na pasta do projeto com o registro completo da execução:
|
||||||
|
|
||||||
|
- data/hora e duração
|
||||||
|
- usuário autenticado
|
||||||
|
- tipo de entidade, filtro, campo e valor aplicado
|
||||||
|
- resumo (total, atualizados, erros)
|
||||||
|
- lista de cada objeto com `status: "updated"` ou `status: "error"`
|
||||||
|
|
||||||
|
Exemplo resumido:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"executedAt": "2026-06-09T15:30:00.000Z",
|
||||||
|
"durationMs": 45230,
|
||||||
|
"userId": "/User/abc123",
|
||||||
|
"operation": {
|
||||||
|
"typeName": "Task",
|
||||||
|
"filter": "Todos",
|
||||||
|
"fieldName": "C_MeuCampo",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"summary": { "total": 10, "updated": 9, "errors": 1 },
|
||||||
|
"results": [
|
||||||
|
{ "id": "/Task/...", "displayName": "Tarefa 1", "status": "updated" },
|
||||||
|
{ "id": "/Task/...", "displayName": "Tarefa 2", "status": "error", "message": "..." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
O caminho do arquivo é exibido no terminal ao final: `Log da execução: ...`
|
||||||
|
|
||||||
## Erros
|
## Erros
|
||||||
|
|
||||||
Objetos que falharem na atualização são listados ao final. Um arquivo `errors-<timestamp>.json` é gerado na pasta do projeto com os detalhes.
|
Objetos que falharem na atualização também aparecem no `run-log-*.json`. Além disso, um arquivo `errors-<timestamp>.json` é gerado quando há falhas, contendo só os erros para reprocessamento.
|
||||||
|
|
||||||
## Observações
|
## Observações
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
import { formatFilterSummary } from "./query/filter.js";
|
import { formatFilterSummary } from "./query/filter.js";
|
||||||
import { fetchAllEntities } from "./query/fetch-all.js";
|
import { fetchAllEntities } from "./query/fetch-all.js";
|
||||||
import { promptEntityFilter } from "./query/prompt-filter.js";
|
import { promptEntityFilter } from "./query/prompt-filter.js";
|
||||||
|
import { buildRunLog, writeRunLog } from "./log/run-log.js";
|
||||||
import { bulkUpdateField } from "./update/bulk-field.js";
|
import { bulkUpdateField } from "./update/bulk-field.js";
|
||||||
import type { FieldDescription, JsonValue } from "@arco/clarizen-lib";
|
import type { FieldDescription, JsonValue } from "@arco/clarizen-lib";
|
||||||
|
|
||||||
@@ -148,6 +149,8 @@ Resumo da operação:
|
|||||||
|
|
||||||
console.log("\nAtualizando...\n");
|
console.log("\nAtualizando...\n");
|
||||||
|
|
||||||
|
const startedAt = Date.now();
|
||||||
|
|
||||||
const result = await bulkUpdateField(
|
const result = await bulkUpdateField(
|
||||||
clarizen,
|
clarizen,
|
||||||
entityChoice.typeName,
|
entityChoice.typeName,
|
||||||
@@ -156,6 +159,20 @@ Resumo da operação:
|
|||||||
parsedValue,
|
parsedValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const logPath = writeRunLog(
|
||||||
|
buildRunLog({
|
||||||
|
startedAt,
|
||||||
|
userId: auth.userId,
|
||||||
|
entityChoice,
|
||||||
|
entityFilter,
|
||||||
|
field,
|
||||||
|
fieldName,
|
||||||
|
parsedValue,
|
||||||
|
records,
|
||||||
|
result,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
if (result.errors.length > 0) {
|
if (result.errors.length > 0) {
|
||||||
const errorFile = resolve(
|
const errorFile = resolve(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
@@ -165,6 +182,8 @@ Resumo da operação:
|
|||||||
console.log(`\n${result.errors.length} erro(s) — detalhes em: ${errorFile}`);
|
console.log(`\n${result.errors.length} erro(s) — detalhes em: ${errorFile}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`\nLog da execução: ${logPath}`);
|
||||||
|
|
||||||
outro(
|
outro(
|
||||||
`Concluído: ${result.updated.toLocaleString("pt-BR")} atualizado(s), ${result.errors.length.toLocaleString("pt-BR")} erro(s).`,
|
`Concluído: ${result.updated.toLocaleString("pt-BR")} atualizado(s), ${result.errors.length.toLocaleString("pt-BR")} erro(s).`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { writeFileSync } from "node:fs";
|
||||||
|
import { resolve } from "node:path";
|
||||||
|
import type { FieldDescription, JsonValue } from "@arco/clarizen-lib";
|
||||||
|
import type { EntityChoice } from "../metadata/picker.js";
|
||||||
|
import { formatFilterSummary, type EntityFilter } from "../query/filter.js";
|
||||||
|
import type { EntityRecord } from "../query/fetch-all.js";
|
||||||
|
import type { BulkUpdateResult } from "../update/bulk-field.js";
|
||||||
|
|
||||||
|
export interface RunLogEntry {
|
||||||
|
id: string;
|
||||||
|
displayName?: string;
|
||||||
|
status: "updated" | "error";
|
||||||
|
message?: string;
|
||||||
|
errorCode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RunLog {
|
||||||
|
executedAt: string;
|
||||||
|
durationMs: number;
|
||||||
|
userId: string;
|
||||||
|
operation: {
|
||||||
|
typeName: string;
|
||||||
|
typeLabel?: string;
|
||||||
|
filter: string;
|
||||||
|
fieldName: string;
|
||||||
|
fieldLabel?: string;
|
||||||
|
fieldType?: string;
|
||||||
|
value: JsonValue;
|
||||||
|
};
|
||||||
|
summary: {
|
||||||
|
total: number;
|
||||||
|
updated: number;
|
||||||
|
errors: number;
|
||||||
|
};
|
||||||
|
results: RunLogEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuildRunLogParams {
|
||||||
|
startedAt: number;
|
||||||
|
userId: string;
|
||||||
|
entityChoice: EntityChoice;
|
||||||
|
entityFilter: EntityFilter;
|
||||||
|
field: FieldDescription;
|
||||||
|
fieldName: string;
|
||||||
|
parsedValue: JsonValue;
|
||||||
|
records: EntityRecord[];
|
||||||
|
result: BulkUpdateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
function logTimestamp(): string {
|
||||||
|
return new Date().toISOString().replace(/[:.]/g, "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildRunLog(params: BuildRunLogParams): RunLog {
|
||||||
|
const {
|
||||||
|
startedAt,
|
||||||
|
userId,
|
||||||
|
entityChoice,
|
||||||
|
entityFilter,
|
||||||
|
field,
|
||||||
|
fieldName,
|
||||||
|
parsedValue,
|
||||||
|
records,
|
||||||
|
result,
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
const errorsById = new Map(
|
||||||
|
result.errors.map((e) => [String(e.id), e] as const),
|
||||||
|
);
|
||||||
|
|
||||||
|
const results: RunLogEntry[] = records.map((record) => {
|
||||||
|
const id = String(record.id);
|
||||||
|
const error = errorsById.get(id);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
displayName: record.displayName,
|
||||||
|
status: "error",
|
||||||
|
message: error.message,
|
||||||
|
errorCode: error.errorCode,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
displayName: record.displayName,
|
||||||
|
status: "updated",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
executedAt: new Date().toISOString(),
|
||||||
|
durationMs: Date.now() - startedAt,
|
||||||
|
userId,
|
||||||
|
operation: {
|
||||||
|
typeName: entityChoice.typeName,
|
||||||
|
typeLabel: entityChoice.label,
|
||||||
|
filter: formatFilterSummary(entityFilter),
|
||||||
|
fieldName,
|
||||||
|
fieldLabel: field.label,
|
||||||
|
fieldType: field.type,
|
||||||
|
value: parsedValue,
|
||||||
|
},
|
||||||
|
summary: {
|
||||||
|
total: records.length,
|
||||||
|
updated: result.updated,
|
||||||
|
errors: result.errors.length,
|
||||||
|
},
|
||||||
|
results,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function writeRunLog(log: RunLog, cwd = process.cwd()): string {
|
||||||
|
const filePath = resolve(cwd, `run-log-${logTimestamp()}.json`);
|
||||||
|
writeFileSync(filePath, JSON.stringify(log, null, 2), "utf-8");
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user