Observability is about the unknown-unknowns; the ability to understand internal system states just by observing its outputs outside.
Charity Majors, Observability Pionerr, Co-Founder of Honeycomb.io
Observability is about the unknown-unknowns; the ability to understand internal system states just by observing its outputs outside.
Charity Majors, Observability Pionerr, Co-Founder of Honeycomb.io
Observability про нефункциональные требования
другие аттрибуты качества — performance, availability, a11y
// Падает в 1% случаев
const checkout = async () => {
if (Math.random() > 0.01) return;
throw new Error("checkout error");
};
app.get("/data", async (req, res) => {
console.log("GET /data request received");
try {
await checkout();
res.status(200).json({ success: true });
} catch (error) {
console.error(error);
res.status(500).json({ success: false });
}
});
Error: checkout error
at checkout (/.../examples/1-simple-express/index.js:9:9)
at /.../examples/1-simple-express/index.js:16:11
at Layer.handleRequest (/.../examples/1-simple-express/node_modules/router/lib/layer.js:152:17)
at next (/.../examples/1-simple-express/node_modules/router/lib/route.js:157:13)
at Route.dispatch (/.../examples/1-simple-express/node_modules/router/lib/route.js:117:3)
at handle (/.../examples/1-simple-express/node_modules/router/index.js:435:11)
at Layer.handleRequest (/.../examples/1-simple-express/node_modules/router/lib/layer.js:152:17)
at /.../examples/1-simple-express/node_modules/router/index.js:295:15
at processParams (/.../examples/1-simple-express/node_modules/router/index.js:582:12)
at next (/.../examples/1-simple-express/node_modules/router/index.js:291:5)
// Падает в 1% случаев
const checkout = async () => {
if (Math.random() > 0.01) return;
throw new Error("checkout error");
};
app.get("/data", async (req, res) => {
console.log("GET /data request received");
try {
await checkout();
res.status(200).json({ success: true });
} catch (error) {
console.error(error);
res.status(500).json({ success: false });
}
});
const log = (msg) => {
console.log(`[${new Date().toISOString()}] ${msg}`);
};
//[2025-04-07T00:19:23.471Z] my log message
log("my log message");
const log = (msg) => {
console.log(`[${new Date().toISOString()}] ${msg}`);
};
//[2025-04-07T00:19:23.471Z] my log message
log("my log message");
Не наш выбор
const log = (msg, level) => {
console.log(`[${new Date().toISOString()}] ${level}: ${msg}`);
};
//[2025-04-07T00:19:23.471Z] Error: my log message
log("my log message" 'Error');
Не наш выбор
// logger.js
module.exports = require("pino")();
//index.js
log = require("./logger");
...
log.info('/data')
try {
await checkout();
res.status(200).json({ success: true });
} catch (error) {
log.error({ error }, 'MySupperError');
res.status(500).json({ success: false });
}
...
{"level":30,"time":1743987006941,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"/data"}
{"level":30,"time":1743987006942,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"success checkout"}
{"level":30,"time":1743987006945,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"/data"}
{"level":30,"time":1743987006945,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"success checkout"}
{"level":30,"time":1743987006946,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"/data"}
{"level":30,"time":1743987006946,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"success checkout"}
{"level":30,"time":1743987006946,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"/data"}
{"level":30,"time":1743987006946,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"success checkout"}
{"level":30,"time":1743987006946,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"/data"}
{"level":30,"time":1743987006946,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"success checkout"}
{"level":30,"time":1743987006947,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"/data"}
{"level":30,"time":1743987006947,"pid":31808,"hostname":"Alexs-MacBook-Pro.local","msg":"success checkout"}
module.exports = require("pino")({
transport: {
target: "pino-pretty",
options: {
colorize: true,
},
},
});
module.exports = require("pino")({
transport: {
target: "pino-pretty",
options: {
colorize: true,
},
},
});
[04:07:27.975] INFO (53569): success checkout
[04:07:28.163] INFO (53569): /checkout
[04:07:28.164] INFO (53569): success checkout
[04:07:28.342] INFO (53569): /checkout
[04:07:28.343] ERROR (53569): error on checkout
err: {
"type": "Error",
"message": "checkout error",
"stack":
Error: checkout error
at checkout (.../examples/2-better-logging/index.js:14:9)
at .../examples/2-better-logging/index.js:21:11
at Layer.handleRequest (.../examples/2-better-logging/node_modules/router/lib/layer.js:152:17)
at next (.../examples/2-better-logging/node_modules/router/lib/route.js:157:13)
at Route.dispatch (.../examples/2-better-logging/node_modules/router/lib/route.js:117:3)
//ЭТО ОЧЕНЬ ПЛОХОЙ КОД, ОН НУЖЕН ДЛЯ ДЕМО. НЕ ПИШИТЕ ТАК
app.use((req, res, next) => {
const id = req.headers["id"] || "no-id";
req.logger = require("./logger.js").child({ "id": id });
next();
});
app.use((req, res, next) => {
const id = req.headers["id"] || "no-id";
req.axios = axios.create({headers: { id }});
next();
});
1. Заголовок traceparent
Version | TraceId | ParentId | TraceFlags |
---|---|---|---|
00 | 0af7651916cd43dd8448eb211c80319c | b7ad6b7169203331 | 01 |
2. Заголовок tracestate
key1=value1;key2=value2— Зачем мне тогда логи, ведь есть трейсы?
— Зачем мне тогда логи, ведь есть трейсы?
— Не все можно описать трейсами!
app.listen(port, () => {
logger.info(`application running on port ${port}`);
});
И все должно работать в связке
→ Вывод: Бесконечная рекурсия из-за ошибки в коде.
→ Вывод: Нужно добавить retry или увеличить лимиты.
→ Вывод: Проблема в запросе к медленной базе данных.
OpenTelemetry, also known as OTel, is a vendor-neutral open source Observability framework for instrumenting, generating, collecting, and exporting telemetry data such as traces, metrics, and logs.
OpenTelemetry, also known as OTel, is a vendor-neutral open source Observability framework for instrumenting, generating, collecting, and exporting telemetry data such as traces, metrics, and logs.
OpenTelemetry (OTel) разрабатывается как open-source проект при поддержке Cloud Native Computing Foundation (CNCF), которая является частью Linux Foundation
Можно пройти бесплатный треннинг (opentelemetry.io/training)
Основная идея
Развиваем
Получаем, преобрузуем, экспортируем
Выбор части данных для обработки/экспорта вместо всей информации
Объединение нескольких данных (например, спанов трейсов) в один пакет перед отправкой.
docker run \
-p 4317:4319 \
-p 4318:4320 \
-p 55679:55679 \
--name telemetry-collector \
otel/opentelemetry-collector-contrib:latest