2026年Ubuntu JS日志存储优化完整指南(2026)

一、为什么需要优化JS日志存储?

在Ubuntu服务器上运行Node.js应用时,日志文件会快速增长,占用大量磁盘空间。如果不加以优化,可能导致:

  • 磁盘空间耗尽,服务崩溃
  • 日志查询效率低下
  • 运维成本增加
  • 难以进行日志分析

优化目标
– 减少磁盘占用
– 提高日志查询效率
– 实现自动轮转和清理
– 保证日志完整性

二、Node.js日志基础配置

2.1 使用Winston日志库

// app.js
const winston = require('winston');
const path = require('path');

// 日志目录
const logDir = '/var/log/nodejs';
if (!require('fs').existsSync(logDir)) {
    require('fs').mkdirSync(logDir, { recursive: true });
}

// 配置日志格式
const logFormat = winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    winston.format.errors({ stack: true }),
    winston.format.splat(),
    winston.format.json()
);

// 创建logger
const logger = winston.createLogger({
    level: process.env.LOG_LEVEL || 'info',
    format: logFormat,
    transports: [
        // 错误日志单独存储
        new winston.transports.File({ 
            filename: path.join(logDir, 'error.log'), 
            level: 'error',
            maxsize: 10485760, // 10MB
            maxFiles: 5
        }),
        // 综合日志
        new winston.transports.File({ 
            filename: path.join(logDir, 'combined.log'),
            maxsize: 10485760,
            maxFiles: 5
        })
    ]
});

// 开发环境输出到控制台
if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple()
    }));
}

module.exports = logger;

2.2 使用Morgan记录HTTP请求

const express = require('express');
const morgan = require('morgan');
const fs = require('fs');
const path = require('path');

const app = express();

// 创建日志流
const accessLogStream = fs.createWriteStream(
    path.join('/var/log/nodejs', 'access.log'),
    { flags: 'a' }
);

// 使用morgan中间件
app.use(morgan('combined', { stream: accessLogStream }));

// 开发环境输出到控制台
if (process.env.NODE_ENV !== 'production') {
    app.use(morgan('dev'));
}

app.get('/', (req, res) => {
    logger.info('Homepage accessed');
    res.send('Hello World');
});

app.listen(3000, () => {
    logger.info('Server started on port 3000');
});

三、配置logrotate自动轮转

3.1 创建logrotate配置文件

sudo nano /etc/logrotate.d/nodejs

添加以下内容:

/var/log/nodejs/*.log {
    daily                  # 每天轮转
    missingok             # 忽略缺失文件
    rotate 14             # 保留14个备份
    compress             # 压缩旧日志
    delaycompress        # 延迟压缩(下次轮转时压缩)
    notifempty          # 不轮转空文件
    create 0640 nodejs nodejs  # 新文件权限
    sharedscripts       # 脚本只执行一次
    postrotate
        # 发送SIGUSR2信号给Node.js进程,重新打开日志文件
        kill -SIGUSR2 $(cat /var/run/nodejs.pid)
    endscript
}

3.2 测试logrotate配置

# 测试配置(不实际执行)
sudo logrotate -d /etc/logrotate.d/nodejs

# 强制轮转(测试用)
sudo logrotate -f /etc/logrotate.d/nodejs

# 查看轮转后的文件
ls -lh /var/log/nodejs/

3.3 按大小轮转

如果日志增长很快,可以按大小轮转:

/var/log/nodejs/*.log {
    size 100M             # 超过100MB时轮转
    missingok
    rotate 7
    compress
    delaycompress
    notifempty
    create 0640 nodejs nodejs
    postrotate
        kill -SIGUSR2 $(cat /var/run/nodejs.pid)
    endscript
}

四、日志压缩与归档

4.1 手动压缩历史日志

# 压缩7天前的日志
find /var/log/nodejs/ -name "*.log.*" -mtime +7 -exec gzip {} \;

# 删除30天前的压缩日志
find /var/log/nodejs/ -name "*.log.*.gz" -mtime +30 -delete

4.2 自动压缩脚本

创建自动压缩脚本:

#!/bin/bash
# /opt/scripts/compress_nodejs_logs.sh

LOG_DIR="/var/log/nodejs"
RETENTION_DAYS=30

echo "[$(date)] 开始压缩Node.js日志..."

# 压缩7天前的日志
find "$LOG_DIR" -name "*.log.*" -mtime +7 ! -name "*.gz" -exec gzip {} \;

# 删除30天前的压缩日志
find "$LOG_DIR" -name "*.log.*.gz" -mtime +$RETENTION_DAYS -delete

# 查看压缩后的空间占用
echo "压缩后的日志目录大小:"
du -sh "$LOG_DIR"

echo "[$(date)] 日志压缩完成"

添加执行权限并配置定时任务:

sudo chmod +x /opt/scripts/compress_nodejs_logs.sh

# 每天凌晨2点执行
sudo crontab -e
0 2 * * * /opt/scripts/compress_nodejs_logs.sh >> /var/log/nodejs/compress.log 2>&1

五、使用Systemd Journal存储日志

5.1 配置Systemd存储Node.js日志

编辑Node.js服务的systemd配置:

sudo nano /etc/systemd/system/nodejs.service

配置内容:

[Unit]
Description=Node.js Application
After=network.target

[Service]
Type=simple
User=nodejs
WorkingDirectory=/opt/app
ExecStart=/usr/bin/node app.js
Restart=on-failure

# 日志配置
StandardOutput=journal
StandardError=journal
SyslogIdentifier=nodejs-app

# 环境变量
Environment=NODE_ENV=production
Environment=LOG_LEVEL=info

[Install]
WantedBy=multi-user.target

5.2 查看Journal日志

# 查看Node.js应用日志
sudo journalctl -u nodejs.service -f

# 查看指定时间段的日志
sudo journalctl -u nodejs.service --since "2026-01-01" --until "2026-01-02"

# 按日志级别过滤
sudo journalctl -u nodejs.service -p err

# 导出日志到文件
sudo journalctl -u nodejs.service --since "2026-01-01" > nodejs-logs-2026-01-01.log

5.3 限制Journal日志大小

编辑systemd配置:

sudo nano /etc/systemd/journald.conf

修改以下配置:

[Journal]
Storage=persistent
Compress=yes
Seal=yes
SizeLimit=500M
MaxFileSec=7day
MaxRetentionSec=30day

重启journald服务:

sudo systemctl restart systemd-journald

六、集中化日志管理

6.1 使用ELK Stack (Elasticsearch + Logstash + Kibana)

安装ELK Stack

# 安装Elasticsearch
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
sudo sh -c 'echo "deb https://artifacts.elastic.co/packages/8.x/apt stable main" > /etc/apt/sources.list.d/elastic-8.x.list'
sudo apt update
sudo apt install elasticsearch logstash kibana

配置Logstash

sudo nano /etc/logstash/conf.d/nodejs.conf
input {
    file {
        path => "/var/log/nodejs/combined.log"
        start_position => "beginning"
        codec => "json"
    }
}

filter {
    if [level] == "error" {
        mutate {
            add_tag => ["alert"]
        }
    }
}

output {
    elasticsearch {
        hosts => ["localhost:9200"]
        index => "nodejs-logs-%{+YYYY.MM.dd}"
    }
}

6.2 使用Fluentd + Elasticsearch

安装Fluentd:

curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-focal-td-agent4.sh | sh

配置Fluentd:

# /etc/td-agent/td-agent.conf
<source>
    @type tail
    path /var/log/nodejs/combined.log
    pos_file /var/log/td-agent/nodejs.pos
    tag nodejs.log
    <parse>
        @type json
    </parse>
</source>

<match nodejs.**>
    @type elasticsearch
    host localhost
    port 9200
    index_name nodejs-logs
    type_name _doc
</match>

七、日志存储优化最佳实践

7.1 日志级别管理

// 根据环境设置日志级别
const getLogLevel = () => {
    const env = process.env.NODE_ENV;
    if (env === 'production') return 'warn';
    if (env === 'test') return 'error';
    return 'debug';
};

logger.level = getLogLevel();

7.2 日志采样

对于高流量应用,使用日志采样减少存储压力:

const logger = require('./logger');

// 采样率10%
const shouldLog = () => Math.random() < 0.1;

app.get('/api/data', (req, res) => {
    if (shouldLog()) {
        logger.info('API /api/data accessed', {
            ip: req.ip,
            userAgent: req.get('User-Agent')
        });
    }
    res.json({ data: 'test' });
});

7.3 异步日志写入

使用Bunyan等支持异步写入的日志库:

const bunyan = require('bunyan');
const RotatingFileStream = require('bunyan-rotating-file-stream');

const logger = bunyan.createLogger({
    name: 'app',
    streams: [{
        type: 'rotating-file',
        path: '/var/log/nodejs/app.log',
        period: '1d',
        count: 7,
        level: 'info'
    }, {
        type: 'rotating-file',
        path: '/var/log/nodejs/error.log',
        period: '1d',
        count: 7,
        level: 'error'
    }]
});

八、监控与告警

8.1 磁盘空间监控

#!/bin/bash
# /opt/scripts/check_log_disk.sh

LOG_DIR="/var/log/nodejs"
THRESHOLD=80

USAGE=$(df -h "$LOG_DIR" | awk 'NR==2 {print $5}' | sed 's/%//')

if [ $USAGE -gt $THRESHOLD ]; then
    echo "警告:日志目录磁盘使用率${USAGE}%,超过${THRESHOLD}%" | \
        mail -s "Node.js日志磁盘告警" admin@example.com
fi

配置定时检查:

# 每小时检查一次
0 * * * * /opt/scripts/check_log_disk.sh

8.2 日志大小告警

// 检查日志文件大小
const checkLogSize = () => {
    const fs = require('fs');
    const path = require('path');

    const logDir = '/var/log/nodejs';
    const files = fs.readdirSync(logDir);

    files.forEach(file => {
        const filePath = path.join(logDir, file);
        const stats = fs.statSync(filePath);
        const sizeMB = stats.size / (1024 * 1024);

        if (sizeMB > 100) {
            logger.warn(`日志文件过大: ${file}, 大小: ${sizeMB.toFixed(2)}MB`);
        }
    });
};

// 每小时检查一次
setInterval(checkLogSize, 60 * 60 * 1000);

九、总结

优化Ubuntu JS日志存储是确保Node.js应用稳定运行的重要环节:

  • 使用专业日志库:Winston、Morgan、Bunyan
  • 配置logrotate:自动轮转、压缩、清理
  • 集中化管理:ELK Stack、Fluentd
  • 监控告警:磁盘空间、日志大小
  • 最佳实践:日志级别、采样、异步写入

通过这些方法,可以有效控制日志存储成本,提高运维效率。

本文基于Ubuntu 22.04 + Node.js 22.x编写,适用于大多数生产环境。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注