feat: rotating log files by time instead of file size

This commit is contained in:
acgnhik 2022-11-06 12:15:11 +08:00
parent 3a7facce0b
commit d4a4904d54
10 changed files with 24 additions and 56 deletions

View File

@ -10,6 +10,6 @@
<body>
<app-root></app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
<script src="runtime.af0deb37647841b9.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.dbd09d2079405adc.js" type="module"></script>
<script src="runtime.0560bf422fb1ab67.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.dbd09d2079405adc.js" type="module"></script>
</body></html>

View File

@ -1,6 +1,6 @@
{
"configVersion": 1,
"timestamp": 1666085654716,
"timestamp": 1667707262978,
"index": "/index.html",
"assetGroups": [
{
@ -15,14 +15,14 @@
"/146.5a8902910bda9e87.js",
"/183.ee55fc76717674c3.js",
"/45.c90c3cea2bf1a66e.js",
"/548.5d742bcea753ec09.js",
"/548.91bbb60199d9e944.js",
"/91.3c224fe84835dadd.js",
"/common.858f777e9296e6f2.js",
"/index.html",
"/main.dbd09d2079405adc.js",
"/manifest.webmanifest",
"/polyfills.4b08448aee19bb22.js",
"/runtime.af0deb37647841b9.js",
"/runtime.0560bf422fb1ab67.js",
"/styles.2e152d608221c2ee.css"
],
"patterns": []
@ -1638,7 +1638,7 @@
"/146.5a8902910bda9e87.js": "d9c33c7073662699f00f46f3a384ae5b749fdef9",
"/183.ee55fc76717674c3.js": "2628c996ec80a6c6703d542d34ac95194283bcf8",
"/45.c90c3cea2bf1a66e.js": "e5bfb8cf3803593e6b8ea14c90b3d3cb6a066764",
"/548.5d742bcea753ec09.js": "1ae82ced33a49e48520babe08fcc030fb8f595e6",
"/548.91bbb60199d9e944.js": "062b3a6424284294e5774bcb08ca76df7b0c4216",
"/91.3c224fe84835dadd.js": "2e3cdb6c44a8cf3241fe8dd89b27c37f212768f8",
"/assets/animal/panda.js": "fec2868bb3053dd2da45f96bbcb86d5116ed72b1",
"/assets/animal/panda.svg": "bebd302cdc601e0ead3a6d2710acf8753f3d83b1",
@ -3234,11 +3234,11 @@
"/assets/twotone/warning.js": "fb2d7ea232f3a99bf8f080dbc94c65699232ac01",
"/assets/twotone/warning.svg": "8c7a2d3e765a2e7dd58ac674870c6655cecb0068",
"/common.858f777e9296e6f2.js": "b68ca68e1e214a2537d96935c23410126cc564dd",
"/index.html": "77dfa5e5defa4b9918c19b2bef05ca991bdec934",
"/index.html": "17482e27906b5ae0447920edbf4bf4f4c0c1838b",
"/main.dbd09d2079405adc.js": "2f7284b616ed9fc433b612c9dca53dc06a0f3aa1",
"/manifest.webmanifest": "62c1cb8c5ad2af551a956b97013ab55ce77dd586",
"/polyfills.4b08448aee19bb22.js": "8e73f2d42cc13ca353cea5c886d930bd6da08d0d",
"/runtime.af0deb37647841b9.js": "79436e2995b15139193a457ad96e453a00af6844",
"/runtime.0560bf422fb1ab67.js": "74c07903a5fd6d43a0d7690a93b0927f8eead22c",
"/styles.2e152d608221c2ee.css": "9830389a46daa5b4511e0dd343aad23ca9f9690f"
},
"navigationUrls": [

View File

@ -1 +1 @@
(()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],c=!0,l=0;l<t.length;l++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,o<a&&(a=o));if(c){e.splice(n--,1);var d=i();void 0!==d&&(f=d)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return r.d(f,{a:f}),f},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",91:"3c224fe84835dadd",103:"5b5d2a6e5a8a7479",146:"5a8902910bda9e87",183:"ee55fc76717674c3",548:"5d742bcea753ec09",592:"858f777e9296e6f2"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="blrec:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,c;if(void 0!==o)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==f+o){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=f=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(f))})(),r.p="",(()=>{var e={666:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=i){var a=new Promise((u,s)=>n=e[i]=[u,s]);o.push(n[2]=a);var c=r.p+r.u(i),l=new Error;r.l(c,u=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+i+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var l,d,[n,a,c]=o,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(i&&i(o);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();
(()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],c=!0,l=0;l<t.length;l++)(!1&o||a>=o)&&Object.keys(r.O).every(p=>r.O[p](t[l]))?t.splice(l--,1):(c=!1,o<a&&(a=o));if(c){e.splice(n--,1);var d=i();void 0!==d&&(f=d)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return r.d(f,{a:f}),f},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",91:"3c224fe84835dadd",103:"5b5d2a6e5a8a7479",146:"5a8902910bda9e87",183:"ee55fc76717674c3",548:"91bbb60199d9e944",592:"858f777e9296e6f2"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="blrec:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,c;if(void 0!==o)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==f+o){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var s=(g,p)=>{a.onerror=a.onload=null,clearTimeout(b);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(p)),g)return g(p)},b=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=f=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(f))})(),r.p="",(()=>{var e={666:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=i){var a=new Promise((u,s)=>n=e[i]=[u,s]);o.push(n[2]=a);var c=r.p+r.u(i),l=new Error;r.l(c,u=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),b=u&&u.target&&u.target.src;l.message="Loading chunk "+i+" failed.\n("+s+": "+b+")",l.name="ChunkLoadError",l.type=s,l.request=b,n[1](l)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var l,d,[n,a,c]=o,u=0;if(n.some(b=>0!==e[b])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(i&&i(o);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();

View File

@ -1,19 +1,18 @@
import os
import logging
from logging import LogRecord, Handler
from logging.handlers import RotatingFileHandler
from datetime import datetime
import asyncio
import threading
import atexit
import logging
import os
import threading
from datetime import datetime
from logging import Handler, LogRecord
from logging.handlers import TimedRotatingFileHandler
from typing import Any, List, Optional
from colorama import init, deinit, Fore, Back, Style
from colorama import Back, Fore, Style, deinit, init
from tqdm import tqdm
from .typing import LOG_LEVEL
__all__ = 'configure_logger', 'ConsoleHandler', 'TqdmOutputStream'
@ -57,7 +56,7 @@ def obtain_room_id() -> str:
name = task.get_name()
if '::' in name:
if (room_id := name.split('::')[-1]):
if room_id := name.split('::')[-1]:
return room_id
return ''
@ -66,7 +65,7 @@ def obtain_room_id() -> str:
def record_factory(*args: Any, **kwargs: Any) -> LogRecord:
record = _old_factory(*args, **kwargs)
if (room_id := obtain_room_id()):
if room_id := obtain_room_id():
record.roomid = '[' + room_id + '] ' # type: ignore
else:
record.roomid = '' # type: ignore
@ -84,7 +83,6 @@ def configure_logger(
log_dir: str,
*,
console_log_level: LOG_LEVEL = 'INFO',
max_bytes: Optional[int] = None,
backup_count: Optional[int] = None,
) -> None:
# config root logger
@ -104,10 +102,10 @@ def configure_logger(
# logging to file
log_file_path = make_log_file_path(log_dir)
file_handler = RotatingFileHandler(
log_file_path,
maxBytes=max_bytes or 1024 ** 2 * 10,
backupCount=backup_count or 1,
file_handler = TimedRotatingFileHandler(
filename=log_file_path,
when='MIDNIGHT',
backupCount=backup_count or 0,
encoding='utf-8',
)
file_handler.setLevel(logging.DEBUG)

View File

@ -326,12 +326,7 @@ def log_dir_factory() -> str:
class LoggingSettings(BaseModel):
log_dir: Annotated[str, Field(default_factory=log_dir_factory)]
console_log_level: LOG_LEVEL = 'INFO'
max_bytes: Annotated[
int, Field(ge=1024**2, le=1024**2 * 10, multiple_of=1024**2)
] = (
1024**2 * 10
) # allowed 1 ~ 10 MB
backup_count: Annotated[int, Field(ge=1, le=30)] = 30
backup_count: Annotated[int, Field(ge=0, le=90)] = 30
@validator('log_dir')
def _validate_dir(cls, path: str) -> str:

View File

@ -265,7 +265,6 @@ class SettingsManager:
configure_logger(
log_dir=self._settings.logging.log_dir,
console_log_level=self._settings.logging.console_log_level,
max_bytes=self._settings.logging.max_bytes,
backup_count=self._settings.logging.backup_count,
)

View File

@ -36,19 +36,6 @@
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="setting-item">
<nz-form-label class="setting-label" nzNoColon
>日志文件分割大小</nz-form-label
>
<nz-form-control
class="setting-control select"
[nzWarningTip]="syncFailedWarningTip"
[nzValidateStatus]="syncStatus.maxBytes ? maxBytesControl : 'warning'"
>
<nz-select formControlName="maxBytes" [nzOptions]="maxBytesOptions">
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="setting-item">
<nz-form-label class="setting-label" nzNoColon
>日志文件备份数量</nz-form-label

View File

@ -42,12 +42,7 @@ export class LoggingSettingsComponent implements OnInit, OnChanges {
{ label: 'CRITICAL', value: 'CRITICAL' },
];
readonly maxBytesOptions = range(1, 11).map((i) => ({
label: `${i} MB`,
value: 1024 ** 2 * i,
}));
readonly backupOptions = range(1, 31).map((i) => ({
readonly backupOptions = range(0, 91).map((i) => ({
label: i.toString(),
value: i,
}));
@ -60,7 +55,6 @@ export class LoggingSettingsComponent implements OnInit, OnChanges {
this.settingsForm = formBuilder.group({
logDir: [''],
consoleLogLevel: [''],
maxBytes: [''],
backupCount: [''],
});
}
@ -73,10 +67,6 @@ export class LoggingSettingsComponent implements OnInit, OnChanges {
return this.settingsForm.get('consoleLogLevel') as FormControl;
}
get maxBytesControl() {
return this.settingsForm.get('maxBytes') as FormControl;
}
get backupCountControl() {
return this.settingsForm.get('backupCount') as FormControl;
}

View File

@ -113,7 +113,6 @@ export type LogLevel =
export interface LoggingSettings {
logDir: string;
consoleLogLevel: LogLevel;
maxBytes: number;
backupCount: number;
}