This is a creation in Article, where the information may have evolved or changed.
@description Logging Tool class/* Log format: Time (System time) log type (method settings) log content (dynamic Input) Log class contains two sync locks: Buffer lock-mu_buf file lock-mu_ File log input operation PrintfPrintln1. Get buffer lock 2. Write buffer 3. Release buffer lock 4.A. Call bufwrite,b. Wait for a timed call Bufwrite log output operation bufWrite1. get file lock 2. Determine the buffer, Returns 3 without writing. Gets the buffer lock 4. Write buffer 5. Release buffer lock log listener operation Filemonitora. File Listener Timer expires FileCheck1. Determine if the file name is required. and follow-up 1.1. Get the file lock 1.2. Re-determine if the file requires a duplicate name 1.3. rename file 1.4. Release file lock B. Timed write timer expires bufwrite file timed write bufwrite and file listener filemonitor time interval T1, T2 prevent file collisions (in seconds) need to meet (n-1) t1%60! = (n-1) t2%60 order get Lock: Buffer Lock--file lock *///@author hanse//@data 2016-08-0413:39 Debug Code no error// 2017-04-0817:04 modifies the Bufwrite acquisition lock mechanism, writes the thread implementation, adds the necessary design instructions//2017-05-2421:11 code structure adjustment, merges the non-unwanted method, dynamically sets the detection and write events, The timer is reset to the package loggorimport ("bytes" "Encoding/json" "FMT" "io" "Log" "Math" "OS" "Path" "Runtime/debug" "Sync" "Time") Const (_version_ = "1.0.1"//version DateFormat = "2006-01-02"//Date format (for file naming) TimeFormat = "2006/01/02 15:04:05"//Time format (log time format) _space = ""//Parameter split _table = "\ T" Log file line delimiter _join = "&" Parameter connector _file_operat_mode_ = 0644//File operation permission Mode _file_creat_mode_ = 0666//File build right Limited mode _label_ = "[_loggor_]"//label) const (//log file storage mode Log_file_save_usual = 1//Normal mode, not split log_file_save_size = 2//size Split log_file_save_date = 3//date Split) const (//File size Unit _ = iotakb Int64 = 1 << (iota *) MBGBTB) const (_ext en_name_ = ". Log"//log file suffix name _check_time_ time. Duration = * time. Millisecond//timing detection whether to split the detection period _write_time_ time. Duration = 1300 * time. Millisecond//timed write file period var (is_debug = false//debug Mode Timeer_write = False//timed write file) type LOGGER interface {setdebug (bool) Set log file path and name Settype (UINT)//set Log type SETROLLINGF Ile (String, String, Int32, Int64, Int64)//split by File size setrollingdaily (string, String)//split by date SETROLLINGN Ormal (String, String)//Set Normal mode close ()//Close println (a ... interface{})//print log printf (format string, a ... interface{})//formatted output}/ /================================================================== Logger type Logger struct {log_type uint//day Log type path string//logfile path dir string//directory filename string//filename maxfilesize Int64 File Size maxfilecount Int32//File number dailyrolling bool//day split sizerolling bool//Size split nomalrolling BOOL//Normal mode (not split) _suffix int//size split file's current sequence number _date *time. Time//file times Mu_buf *sync. Mutex//Buffer lock Mu_file *sync. Mutex//File lock logfile *os. File//Files handle timer *time. Timer//monitor timer Writetimer *time. Timer//Batch write timer BUF *bytes. Buffer//buffers (common BUF guarantees the order of data writes)}/** Gets the log object **/func New () *logger {this: = &logger{}this.buf = &bytes. Buffer{}this.mu_buf = new (sync. Mutex) This.mu_file = new (sync. Mutex) return this}/** format line output **/func (this *logger) Printf (formAt string, a ... interface{}) {defer func () {if! Timeer_write {go This.bufwrite ()}} () TP: = FMT. Sprintf (format, a ...) This.mu_buf. Lock () defer this.mu_buf. Unlock () this.buf.WriteString (FMT. Sprintf ("%s\t%d\t%s\n", time. Now (). Format (TimeFormat), THIS.LOG_TYPE,TP,),}/** progressive output **/func (this *logger) Println (a ... interface{}) {defer func () {if! Timeer_write {go This.bufwrite ()}} () TP: = FMT. Sprint (A ...) This.mu_buf. Lock () defer this.mu_buf. Unlock () this.buf.WriteString (FMT. Sprintf ("%s\t%d\t%s\n", time. Now (). Format (TimeFormat), THIS.LOG_TYPE,TP,),}/** test mode **/func (this *logger) Setdebug (is_debug bool) {is_debug = is_debug}/* * Timed Write **/func (this *logger) settimewrite (time_write bool) *logger {timeer_write = time_writereturn this}/** log type **/func ( This *logger) SetType (tp uint) {This.log_type = tp}/** size split **/func (this *logger) setrollingfile (dir, _file string, MAXN in T32, Maxs Int64, _u Int64) {//0. Input legality if this.sizerolling | | this.dailyrolling | | this.nomalrolling {log. Println (_label_, "mode can ' t be changed!") RetURN}//1. Set each pattern marker this.sizerolling = truethis.dailyrolling = Falsethis.nomalrolling = False//2. Set the logger parameters This.maxfilecount = Maxnthis.maxfilesize = Maxs * Int64 (_u) This.dir = Dirthis.filename = _filefor I: = 1; I <= int (MAXN); i++ {sizefile: = FMT. Sprintf (Dir,_file,_exten_name_, ".", FMT. Sprintf ("%05d", I),) if Isexist (sizefile) {this._suffix = i} else {Break}}//3. Real-time file Write This.path = fmt. Sprint (Dir,_file,_exten_name_,) This.startlogger (This.path)}/** date split **/func (this *logger) setrollingdaily (dir, _ File string) {//0. Input legitimacy if this.sizerolling | | this.dailyrolling | | this.nomalrolling {log. Println (_label_, "mode can ' t be changed!") RETURN}//1. Set each pattern marker this.sizerolling = falsethis.dailyrolling = Truethis.nomalrolling = false//2. Set Logger Parameters This.dir = Dirthis.filename = _filethis._date = Getnowformdate (DateFormat) This.startlogger (FMT. Sprint (This.dir,this.filename,_exten_name_, ".", This._date. Format (DateFormat),)}/** Normal mode **/func (this *logger) setrollingnormal (dir, _file string) {//0. Input legitimacy if This.sizerollinG | | this.dailyrolling | | this.nomalrolling {log. Println (_label_, "mode can ' t be changed!") RETURN}//1. Set each pattern marker this.sizerolling = falsethis.dailyrolling = Falsethis.nomalrolling = true//2. Set Logger Parameters This.dir = Dirthis.filename = _filethis.startlogger (FMT. Sprint (Dir,_file,_exten_name_,),}/** close the logger **/func (this *logger) close () {//0. Get lock This.mu_buf. Lock () defer this.mu_buf. Unlock () This.mu_file. Lock () defer this.mu_file. Unlock ()//1. Close if nil! = This.timer {this.timer.Stop ()}if nil! = This.writetimer {this.writeTimer.Stop ()}if this.logfile ! = Nil {err: = This.logfile.Close () if err! = Nil {log. Println (_label_, "File Close err", err)}} else {log. Println (_label_, "file has been closed!")} 2. Clean this.sizerolling = falsethis.dailyrolling = Falsethis.nomalrolling = false}//================================= ================================= Internal Tool method//Initial logger (unified invocation of each logger) func (this *logger) Startlogger (TP string) {defer func () { If e, OK: = Recover (). (error); OK {log. Println (_label_, "Warn:panic-%v", e) log. PrintlN (_label_, String (Debug). Stack ()))}} ()//1. Initialize the space var err errorthis.buf = &bytes. Buffer{}this.mu_buf = new (sync. Mutex) This.mu_file = new (sync. Mutex) This.path = TPCHECKFILEDIR (TP) this.logfile, err = os. OpenFile (Tp,os. O_rdwr|os. O_append|os. O_create,_file_operat_mode_,) if nil! = Err {log. Println (_label_, "OpenFile err!")} 2. Turn on monitor thread go func () {This.timer = time. Newtimer (_check_time_) This.writetimer = time. Newtimer (_write_time_) if! Timeer_write {this.writeTimer.Stop ()}for {select {///timed detect if split case <-this.timer.c:this.filecheck () if Is_debug & & False {log. Printf ("*")//Heartbeat}break//timed write to file (timed write, will cause delay) Case <-this.writetimer.c:this.bufwrite () if Is_debug && false { Log. Printf (".")//Heartbeat}break}}} () If Is_debug {jstr, err: = json. Marshal (this) if nil = = Err {log. Println (_label_, _version_, String (jstr))}}}//file detection (locks file) func (this *logger) FileCheck () {//0. Boundary judgment if nil = = This.mu_ File | | Nil = = This.logfile | | "" = = This.path {return}defer func () {if e, ok: = Recover (). ( Error); OK {log. PrintlN (_label_, "Warn:panic-%v", e) log. Println (_label_, String (Debug. Stack ()))}} ()//1. Rename to determine var rename_flag bool = Falsevar check_time time. Duration = _check_time_this.timer.stop () defer this.timer.Reset (check_time) if this.dailyrolling {//day split mode now: = Getnowformdate (DateFormat) if nil! = Now &&nil! = This._date &&now. After (*this._date) {//timeout name Rename_flag = true} else {//detection interval dynamically adjusts du: = This._date. Unixnano ()-now. Unixnano () ABS: = Math. Abs (Float64 (du)) Check_time = Check_time * time. Duration (Abs/abs)}} else if this.sizerolling {//File size mode if ""! = This.path &&this.maxfilecount >= 1 &&fi Lesize (This.path) >= this.maxfilesize {//excess duplicate name Rename_flag = true}} else if this.nomalrolling {//Normal mode Rename_flag = False }//2. Duplicate operation if Rename_flag {this.mu_file. Lock () defer this.mu_file. Unlock () if Is_debug {log. Println (_label_, This.path, "is need rename.")} This.filerename ()}return}//Rename file func (this *logger) Filerename () {//1. generate file name var err errorvar newName Stringvar oldname StringdefeR func () {if is_debug {log. Println (_label_,oldname, "--", NewName, ":", Err,)}} () if this.dailyrolling {//Date split mode (file not renamed) Oldname = This.pathnewname = This.paththis._date = Getnowformdate (dateformat) This.path = FMT. Sprint (This.dir,this.filename,_exten_name_, ".", This._date. Format (DateFormat),)} else if this.sizerolling {//Size split mode (...) suffix: = Int (This._suffix%int (this.maxfilecount) + 1) oldname = This.pathnewname = Fmt. Sprint (This.path, ".", FMT. Sprintf ("%05d", suffix),) This._suffix = Suffixthis.path = This.path} else if this.nomalrolling {//General mode}//2. Handle old files This.logfile.Close () if ""! = Oldname && "! = NewName && Oldname! = newName {if isexist (newName) {//delete In addition to the old file err: = OS. Remove (newName) if nil! = Err {log. Println (_label_, "Remove file Err", Err. Error ())}}err = OS. Rename (Oldname, newName) if err! = Nil {//duplicate name of old file log. Println (_label_, "Rename file Err", Err. Error ())}}//3. Create a new file this.logfile, err = os. OpenFile (This.path,os. O_rdwr|os. O_append|os. O_create,_file_operat_mode_,) if err! = NIl {log. Println (_label_, "creat file Err", Err. Error ())}return}//buffered Write file func (this *logger) Bufwrite () {//0. boundary processing if nil = = This.buf | | "" = = This.path | | Nil = = This.logfile | | Nil = = This.mu_buf | | Nil = = This.mu_file | | This.buf.Len () <= 0 {return}//1. Data written to Var write_time time. Duration = _write_time_if Nil! = This.writetimer {this.writeTimer.Stop () defer This.writeTimer.Reset (Write_time)} This.mu_file. Lock () defer this.mu_file. Unlock () this.mu_buf. Lock () defer this.mu_buf. Unlock () defer this.buf.Reset () n, err: = Io. WriteString (This.logfile, this.buf.String ()) if nil! = Err {//write failed, checksum file not present create Checkfiledir (This.path) This.logfile, Err = OS. OpenFile (This.path,os. O_rdwr|os. O_append|os. O_create,_file_operat_mode_,) if nil! = Err {log. Println (_label_, "Log bufwrite () err!")}} Dynamically set the write interval according to the buffer pressure if n = = 0 {write_time = _write_time_} else {write_time = Write_time * time. Duration (n/n)}}//================================================================== helper method//Get File size func fileSize ( File string) Int64 {this, E: =Os. Stat (file) if E! = Nil {if Is_debug {log. Println (_label_, E.error ())}return 0}return this. Size ()}//determines if the path exists with the Func isexist (path string) bool {_, Err: = OS. Stat (path) return err = = Nil | | Os. Isexist (ERR)}//checks the file path folder, does not exist then creates a Func checkfiledir (TP string) {p, _: = path. Split (TP) d, err: = OS. Stat (P) if err! = Nil | | !d.isdir () {if err: = OS. Mkdirall (P, _file_creat_mode_); Err! = Nil {log. Println (_label_, "Checkfiledir () creat dir faile!")}}} Gets the date of the current specified format, func getnowformdate (Form string) *time. Time {T, err: = time. Parse (form, time. Now (). Format (form)) if nil! = Err {log. Println (_label_, "getnowformdate ()", Err. Error ()) T = time. Time{}return &t}return &t}//================================================================== test Case func Test () {logg: = New () Logg. SetType (1) logg. Setrollingnormal ("./logs", "Logg") Logg. Println ("Hello world!")}
Simple Use cases:
var synloger Logger = logger{} synloger.settype (config. Log_type_unknow) synloger.setrollingnormal (path. Split (config. Log_path_root + "/" + CONFIG. Log_path_syncer))
1616 Reads