├── .gitignore ├── LICENSE ├── README.md ├── log-master.js ├── package.json └── test ├── split-on-writing ├── app.js ├── bin │ └── www ├── log-split.js ├── loop.js ├── nohup.out └── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /test/split-on-writing/node_modules 3 | /test/split-on-writing/package-lock.json 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # log-master 1.0.0 2 | 简单的Log定时切割工具。可切割正在被写入的log文件,并保持完整性。 3 | 4 | 不支持window平台。 5 | 6 | ## 安装 7 | `npm install log-master` 8 | ## 使用方法 9 | ### split 10 | 11 | 将本机上所有log用时间分割,汇集到一个文件夹里。 12 | ```javascript 13 | var logMaster = require('log-master'); 14 | logMaster.split({ //切割,目前唯一的功能 15 | "from": { //源文件夹,可多选。 16 | "forever": "/root/.forever", 17 | "app1": "/app1logdir", 18 | "app2": "/app2logdir" 19 | }, 20 | "Suffix": [".log"], //要切割的文件类型,可多选。默认 [".log"] 21 | "to": __dirname, //目标文件夹,log都会到这里。 22 | "Interval": 1000 * 60 * 60 * 24, //切割时间间隔,默认一天。 23 | "timeFormat": "yyyy年MM月dd日HH时mm分ss秒", //时间格式(生成的文件夹名),默认为yyyy年MM月dd日HH时mm分ss秒 24 | "startTime": "00:00" //开始时间,默认零点,精确到秒的话就:"00:00:00" 25 | }); 26 | ``` 27 | ## 运行 28 | `nohup node youapp.js &` 29 | 30 | 或用其它守护进程比如:`pm2`, `forever` 31 | ## 注意 32 | 手动输出Log时需要使用 **>>** 而不是 **>** 符号。例: 33 | 34 | ### 使用 **>** 将会得到: 35 | 36 | `nohup node ./loop.js >/somedir/you.log &` 37 | 38 | ![image](https://github.com/hezedu/SomethingBoring/blob/master/log-master/log-master-error.png?raw=true)
39 | 在vim下看,切割后的文件会包含之前被清空的占位符,并且体积逐渐增大。 40 | 41 | 42 | ### 使用 **>>** 才会得到你想要的结果。 43 | 44 | `nohup node ./loop.js >>/somedir/you.log &` 45 | 46 | ![image](https://github.com/hezedu/SomethingBoring/blob/master/log-master/log-master-ok.png?raw=true) 47 | -------------------------------------------------------------------------------- /log-master.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | var sas = require('sas'); 3 | var fs = require('fs'); 4 | 5 | var Dateformat = function(date, fmt) { //来自互联网 6 | date = date ? new Date(date) : new Date(); 7 | fmt = fmt || 'yyyy-MM-dd HH:mm:ss'; 8 | var o = { 9 | 'M+': date.getMonth() + 1, 10 | 'd+': date.getDate(), 11 | 'H+': date.getHours(), 12 | 'm+': date.getMinutes(), 13 | 's+': date.getSeconds(), 14 | 'q+': Math.floor((date.getMonth() + 3) / 3), 15 | 'S': date.getMilliseconds() 16 | }; 17 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); 18 | for (var k in o) 19 | if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))); 20 | return fmt; 21 | } 22 | 23 | exports.split = function(conf) { 24 | //conf 25 | var from = conf.from; //源文件夹 26 | var to = conf.to || __dirname; //目标文件夹 27 | 28 | var interval = conf.Interval || 29 | 1000 * 60 * 60 * 24; //间隔 默认一天 30 | 31 | var timeFormat = conf.timeFormat || "yyyy年MM月dd日HH时mm分ss秒"; //文件夹时间名字格式。 32 | 33 | var c_start = conf.startTime || "00:00"; //开始时间 34 | c_start = c_start.split(':'); //开始时间 35 | 36 | var suffix = conf.Suffix || 37 | ['.log']; //后缀 默认['.log'] 38 | 39 | var c_start_Hour = Number(c_start[0]); //开始时间小时 40 | var c_start_min = Number(c_start[1]); //开始时间分钟 41 | var c_start_sec = c_start[2] ? Number(c_start[2]) : 0; //开始时间秒钟 42 | c_start = new Date(); 43 | c_start.setHours(c_start_Hour, c_start_min, c_start_sec); 44 | c_start = c_start.getTime(); 45 | var c_result = {}; //读取源文件列表变量。 46 | var c_time = 0; //时间文件夹名字 47 | //////////////////////// task /////////////////////////// 48 | 49 | var readDir = function(path) { //读取目录下log文件。第一步。 50 | return function(cb, t) { 51 | fs.readdir(path, function(err, flies) { 52 | if (err) { 53 | console.error("读取目录下log文件失败:" + path); 54 | return cb('$STOP', err); 55 | } 56 | //var sharr = []; 57 | var obj = {}; 58 | for (var i = 0, len = flies.length; i < len; i++) { 59 | var flie = flies[i]; 60 | for (var suffix_i = 0, suffix_len = suffix.length; suffix_i < suffix_len; suffix_i++) { 61 | if (flie && flie[0] !== '.' && flie.substr(flie.length - suffix[suffix_i].length) === suffix[suffix_i]) { 62 | c_result[path + '/' + flie] = t.index + '__' + flie; 63 | } 64 | } 65 | } 66 | cb(path); 67 | }); 68 | } 69 | } 70 | 71 | var mkDirTime = function(cb, t) { //2跟据时间创建文件夹 72 | var _now = Date.now(); 73 | c_start = c_start + interval * Math.ceil((_now - c_start) / interval); 74 | var time = Dateformat(c_start, timeFormat); 75 | c_time = time; 76 | console.log('将在:\u001b[91m' + time + " \u001b[39m开始切割。"); 77 | setTimeout(function() { 78 | console.log('正在创建文件夹:' + time); 79 | fs.mkdir(to + '/' + time, function(err) { 80 | if (err) { 81 | console.error("创建目标文件夹失败:" + to + '/' + time); 82 | return cb('$STOP', err); 83 | } 84 | cb(); 85 | }); 86 | }, c_start - _now); 87 | } 88 | 89 | 90 | ///////////////////// task end ///////////////////// 91 | 92 | function _loop() { 93 | sas([from], { 94 | iterator: readDir, 95 | allEnd: function(err, result) { 96 | if (err) { 97 | return console.error('初始化失败:' + err); 98 | } 99 | var _catTasks = {}; 100 | 101 | var _cat = function(cb, t) { 102 | var logPath = t.index; 103 | var newFilePath = to + "/" + c_time + '/' + c_result[logPath] 104 | child_process.execSync('cat ' + logPath + ' > ' + newFilePath + ' && cat /dev/null > ' + logPath); 105 | cb(); 106 | } 107 | for (var i in c_result) { 108 | _catTasks[i] = _cat; 109 | } 110 | sas([mkDirTime, _catTasks, function(cb) { 111 | cb(); 112 | console.log('end'); 113 | _loop(); 114 | }]); 115 | } 116 | }); 117 | } 118 | _loop(); 119 | } 120 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "log-master", 3 | "version": "1.0.0", 4 | "main": "log-master", 5 | "scripts": { 6 | "vminstall": "cnpm i --by=npm --no-bin-links" 7 | }, 8 | "keywords": [ 9 | "log", 10 | "nodejs", 11 | "split" 12 | ], 13 | "files": [ 14 | "log-master.js" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/hezedu/log-master.git" 19 | }, 20 | "author": { 21 | "name": "hezedu" 22 | }, 23 | "dependencies": { 24 | "sas": "0.1.19" 25 | }, 26 | "license": "MIT", 27 | "email": "hezedu@hotmail.com", 28 | "description": "split the log", 29 | "bugs": { 30 | "url": "https://github.com/hezedu/log-master/issues" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/split-on-writing/app.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var express = require('express'); 4 | var path = require('path'); 5 | 6 | 7 | var app = express(); 8 | 9 | var count = 0; 10 | function loop(){ 11 | setTimeout(function(){ 12 | process.stdout.write(count + '|'); 13 | count = count + 1; 14 | loop(); 15 | }) 16 | } 17 | 18 | loop(); 19 | /* 20 | setTimeout(function(){ 21 | process.exit(); 22 | },1000 * 30); 23 | */ 24 | // view engine setup 25 | 26 | // uncomment after placing your favicon in /public 27 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 28 | //app.use(logger('tiny')); 29 | app.use(express.static(path.join(__dirname, 'public'))); 30 | 31 | 32 | // catch 404 and forward to error handler 33 | app.use(function(req, res, next) { 34 | var err = new Error('Not Found'); 35 | err.status = 404; 36 | next(err); 37 | }); 38 | 39 | // error handler 40 | app.use(function(err, req, res, next) { 41 | // set locals, only providing error in development 42 | res.locals.message = err.message; 43 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 44 | 45 | // render the error page 46 | res.status(err.status || 500); 47 | res.render('error'); 48 | }); 49 | 50 | module.exports = app; 51 | -------------------------------------------------------------------------------- /test/split-on-writing/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('express:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '4000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | console.log('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /test/split-on-writing/log-split.js: -------------------------------------------------------------------------------- 1 | var logMaster = require('../../log-master'); 2 | logMaster.split({ //切割,目前唯一的功能 3 | "from": { //源文件夹,可多选。 4 | "loop": "/home/dw/logmaster", 5 | }, 6 | "Suffix": [".log"], //要切割的文件类型,可多选。默认 [".log"] 7 | "to": "/home/dw/s-log", //目标文件夹,log都会到这里。 8 | "Interval": 1000 * 10, //切割时间间隔,默认一天。 9 | "timeFormat": "yyyy年MM月dd日HH时mm分ss秒", //时间格式(生成的文件夹名),默认为yyyy年MM月dd日HH时mm分ss秒 10 | "startTime": "00:00" //开始时间,默认零点,精确到秒的话就:"00:00:00" 11 | }); 12 | 13 | //0 4110 14 | // 15 | // setTimeout(function(){ 16 | // process.exit(); 17 | // },1000 * 30); -------------------------------------------------------------------------------- /test/split-on-writing/loop.js: -------------------------------------------------------------------------------- 1 | var count = 0; 2 | function loop(){ 3 | setTimeout(function(){ 4 | process.stdout.write(count + '|'); 5 | count = count + 1; 6 | loop(); 7 | },100) 8 | } 9 | 10 | loop(); 11 | 12 | // setTimeout(function(){ 13 | // process.exit(); 14 | // },1000 * 30); 15 | 16 | -------------------------------------------------------------------------------- /test/split-on-writing/nohup.out: -------------------------------------------------------------------------------- 1 | warn: --minUptime not set. Defaulting to: 1000ms 2 | warn: --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms 3 | info: Forever processing file: loop.js 4 | -------------------------------------------------------------------------------- /test/split-on-writing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "vminstall": "cnpm i --by=npm --no-bin-links", 7 | "loop_start_by_nohup": "nohup node ./loop.js >>/home/dw/logmaster/loop.log 2>>/home/dw/logmaster/loop-err.log &", 8 | "loop_start_by_forever": "forever start -l /home/dw/logmaster/loop.log -e /home/dw/logmaster/loop-err.log -a loop.js", 9 | "loop_start": "node bin/www >> /home/dw/logmaster/loop.log", 10 | "start": "npm run loop_start && node log-split.js", 11 | "pro": "NODE_ENV=production forever start -l /home/dw/logmaster/all.log -e /home/dw/logmaster/err.log -a bin/www" 12 | }, 13 | "dependencies": { 14 | "express": "~4.16.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var logMaster = require('../log-master'); 2 | 3 | var now = new Date(); 4 | var h = now.getHours(); 5 | var m = now.getMinutes()+1; 6 | logMaster.split({ 7 | "from": { 8 | /* "nodeWeb": "/usr/local/software/node/node_web/log", 9 | "nodeApp": "/usr/local/software/node/node_app/log", 10 | "nodeWap": "/usr/local/software/node/node_wap/log",*/ 11 | //"nodeWechat": "/usr/local/softeware/node-log-master/testtt" 12 | "nodeWechat": "D:/duwei/test/log" 13 | }, 14 | "Suffix":[".log",'.js'], 15 | "to": __dirname, 16 | "Interval": 1000 * 60 , 17 | "timeFormat": "yyyy年MM月dd日HH时mm分ss秒", 18 | "startTime":'1:1:9',//开始 19 | "startTime": h+':'+m+':0'//开始 20 | }); 21 | --------------------------------------------------------------------------------