面试题答案
一键面试日志采集
- 使用
winston
库:winston
是Node.js中广泛使用的日志记录库,可用于灵活配置日志格式和输出目标。- 安装:
npm install winston
- 示例代码:
- 安装:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transport.Console()
]
});
module.exports = logger;
- 在业务代码中记录日志:在每个需要记录日志的地方,引入上述
logger
实例进行日志记录。
const logger = require('./logger');
app.get('/api', (req, res) => {
logger.info('Received request to /api');
// 业务逻辑
res.send('Response');
});
- 结合
express
中间件(如果是Web服务):可以在express
应用中使用中间件记录请求和响应相关的日志。
const express = require('express');
const logger = require('./logger');
const app = express();
app.use((req, res, next) => {
logger.info(`Received ${req.method} request to ${req.url}`);
next();
});
app.get('/api', (req, res) => {
res.send('Response');
});
app.use((err, req, res, next) => {
logger.error(err.message);
res.status(500).send('Internal Server Error');
});
日志传输
- 使用
winston-elasticsearch
:这是winston
的一个传输器,可将日志发送到Elasticsearch。- 安装:
npm install winston-elasticsearch
- 配置:修改
winston
配置,添加Elasticsearch传输器。
- 安装:
const winston = require('winston');
const winstonElasticsearch = require('winston-elasticsearch');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winstonElasticsearch({
level: 'info',
clientOpts: {
node: 'http://localhost:9200'
}
})
]
});
module.exports = logger;
- 消息队列(可选):为了进一步提高性能和可靠性,可以在日志采集和传输之间引入消息队列,如
Kafka
或RabbitMQ
。在Node.js中可以使用相应的客户端库(如kafkajs
for Kafka)。- Kafka示例:
- 安装:
npm install kafkajs
- 生产者代码:
- 安装:
- Kafka示例:
const { Kafka } = require('kafkajs');
const kafka = new Kafka({
clientId: 'logger - producer',
brokers: ['localhost:9092']
});
const producer = kafka.producer();
const run = async () => {
await producer.connect();
const message = { value: JSON.stringify({ message: 'Log message' }) };
await producer.send({
topic: 'log - topic',
messages: [message]
});
await producer.disconnect();
};
run().catch(console.error);
- 消费者代码:
const { Kafka } = require('kafkajs');
const kafka = new Kafka({
clientId: 'logger - consumer',
brokers: ['localhost:9092']
});
const consumer = kafka.consumer({ groupId: 'log - group' });
const run = async () => {
await consumer.connect();
await consumer.subscribe({ topic: 'log - topic', fromBeginning: true });
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
const log = JSON.parse(message.value.toString());
// 这里可以将日志发送到Elasticsearch
}
});
};
run().catch(console.error);
日志存储(Elasticsearch)
- 索引管理:在Elasticsearch中创建合适的索引来存储日志。可以使用
elasticsearch
官方Node.js客户端库进行索引创建和管理。- 安装:
npm install @elastic/elasticsearch
- 创建索引示例:
- 安装:
const { Client } = require('@elastic/elasticsearch');
const client = new Client({ node: 'http://localhost:9200' });
const createIndex = async () => {
try {
const indexName = 'log - index';
const indexSettings = {
settings: {
number_of_shards: 1,
number_of_replicas: 0
},
mappings: {
properties: {
timestamp: { type: 'date' },
level: { type:'string' },
message: { type:'string' }
}
}
};
await client.indices.create({ index: indexName, body: indexSettings });
console.log(`Index ${indexName} created`);
} catch (error) {
console.error('Error creating index:', error);
}
};
createIndex();
- 数据写入:通过
winston - elasticsearch
传输器或消息队列消费者将日志数据写入Elasticsearch。
与分布式追踪系统(Jaeger)集成
- 安装
jaeger - client - nodejs
:这是Jaeger的Node.js客户端库。- 安装:
npm install jaeger - client - nodejs
- 安装:
- 初始化Tracer:在应用入口处初始化Jaeger Tracer。
const initTracer = require('jaeger - client - nodejs').initTracer;
const tracer = initTracer({
serviceName: 'your - service - name',
sampler: {
type: 'const',
param: 1
},
reporter: {
logSpans: true
}
});
module.exports = tracer;
- 在业务代码中使用Tracer:在处理请求等关键业务逻辑处使用Tracer来创建跨度(Span)。
const tracer = require('./tracer');
app.get('/api', (req, res) => {
const span = tracer.startSpan('handle - api - request');
try {
// 业务逻辑
span.finish();
res.send('Response');
} catch (error) {
span.recordException(error);
span.finish();
res.status(500).send('Internal Server Error');
}
});
- 关联日志和追踪:在日志记录中添加追踪相关信息,如Trace ID和Span ID。
const winston = require('winston');
const tracer = require('./tracer');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transport.Console()
]
});
app.get('/api', (req, res) => {
const span = tracer.startSpan('handle - api - request');
const traceId = span.context().toTraceId();
const spanId = span.context().toSpanId();
logger.info({
message: 'Received request to /api',
traceId,
spanId
});
try {
// 业务逻辑
span.finish();
res.send('Response');
} catch (error) {
span.recordException(error);
span.finish();
res.status(500).send('Internal Server Error');
}
});
在Jaeger UI中,可以通过Trace ID来查看整个分布式链路,并且在Elasticsearch中可以通过Trace ID和Span ID来关联相关的日志,实现日志与分布式追踪系统的整合。