From 7992171974079942aeffb753da5e7cd848e071ac Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Tue, 6 Aug 2013 10:50:08 -0700 Subject: [PATCH] bump(github.com/ccding/go-logging): d4e747a24b2af160872a886a430a16ac65f76456 --- .../github.com/ccding/go-logging/.gitignore | 22 ++ .../github.com/ccding/go-logging/LICENSE | 191 +++++++++++++ .../github.com/ccding/go-logging/README.md | 226 +++++++++++++++ .../github.com/ccding/go-logging/example.conf | 3 + .../github.com/ccding/go-logging/example.go | 45 +++ .../ccding/go-logging/logging/commands.go | 98 +++++++ .../ccding/go-logging/logging/fields.go | 236 ++++++++++++++++ .../ccding/go-logging/logging/fields_test.go | 60 ++++ .../ccding/go-logging/logging/formater.go | 62 +++++ .../ccding/go-logging/logging/get_go_id.c | 25 ++ .../ccding/go-logging/logging/level.go | 68 +++++ .../ccding/go-logging/logging/logging.go | 260 ++++++++++++++++++ .../ccding/go-logging/logging/logging_test.go | 71 +++++ .../ccding/go-logging/logging/request.go | 24 ++ .../ccding/go-logging/logging/writer.go | 130 +++++++++ 15 files changed, 1521 insertions(+) create mode 100644 third_party/github.com/ccding/go-logging/.gitignore create mode 100644 third_party/github.com/ccding/go-logging/LICENSE create mode 100644 third_party/github.com/ccding/go-logging/README.md create mode 100644 third_party/github.com/ccding/go-logging/example.conf create mode 100644 third_party/github.com/ccding/go-logging/example.go create mode 100644 third_party/github.com/ccding/go-logging/logging/commands.go create mode 100644 third_party/github.com/ccding/go-logging/logging/fields.go create mode 100644 third_party/github.com/ccding/go-logging/logging/fields_test.go create mode 100644 third_party/github.com/ccding/go-logging/logging/formater.go create mode 100644 third_party/github.com/ccding/go-logging/logging/get_go_id.c create mode 100644 third_party/github.com/ccding/go-logging/logging/level.go create mode 100644 third_party/github.com/ccding/go-logging/logging/logging.go create mode 100644 third_party/github.com/ccding/go-logging/logging/logging_test.go create mode 100644 third_party/github.com/ccding/go-logging/logging/request.go create mode 100644 third_party/github.com/ccding/go-logging/logging/writer.go diff --git a/third_party/github.com/ccding/go-logging/.gitignore b/third_party/github.com/ccding/go-logging/.gitignore new file mode 100644 index 000000000..00268614f --- /dev/null +++ b/third_party/github.com/ccding/go-logging/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/third_party/github.com/ccding/go-logging/LICENSE b/third_party/github.com/ccding/go-logging/LICENSE new file mode 100644 index 000000000..37ec93a14 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/github.com/ccding/go-logging/README.md b/third_party/github.com/ccding/go-logging/README.md new file mode 100644 index 000000000..dbc8187cb --- /dev/null +++ b/third_party/github.com/ccding/go-logging/README.md @@ -0,0 +1,226 @@ +#go-logging +go-logging is a high-performance logging library for golang. +* Simple: It supports only necessary operations and easy to get start. +* Fast: Asynchronous logging without runtime-related fields has an extremely + low delay of about 800 nano-seconds. + +## Getting Started +The stable version is under the `stable` branch, which does never revert and +is fully tested. The tags in `stable` branch indicate the version numbers. + +However, `master` branch is unstable version, and `dev` branch is development +branch. `master` branch merges `dev` branch periodically. + +Btw, all the pull request should be sent to the `dev` branch. + +### Installation +The step below will download the library source code to +`${GOPATH}/src/github.com/ccding/go-logging`. +```bash +go get github.com/ccding/go-logging/logging +``` + +Given the source code downloaded, it makes you be able to run the examples, +tests, and benchmarks. +```bash +cd ${GOPATH}/src/github.com/ccding/go-logging/logging +go get +go run ../example.go +go test -v -bench . +``` + +### Example +go-logging is used like any other Go libraries. You can simply use the library +in this way. +```go +import "github.com/ccding/go-logging/logging" +``` + +Here is a simple example. +```go +package main + +import ( + "github.com/ccding/go-logging/logging" +) + +func main() { + logger, _ := logging.SimpleLogger("main") + logger.SetLevel(logging.DEBUG) + logger.Error("this is a test from error") + logger.Destroy() +} +``` + +### Configuration +#### Construction Functions +It has the following functions to create a logger. +```go +// with BasicFormat and writing to stdout +SimpleLogger(name string) (*Logger, error) +// with BasicFormat and writing to DefaultFileName +BasicLogger(name string) (*Logger, error) +// with RichFormatand writing to DefaultFileName +RichLogger(name string) (*Logger, error) +// with detailed configuration and writing to file +FileLogger(name string, level Level, format string, timeFormat string, file string, sync bool) (*Logger, error) +// with detailed configuration and writing to a writer +WriterLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) +// read configurations from a config file +ConfigLogger(filename string) (*Logger, error) +``` +The meanings of these fields are +```go +name string // logger name +level Level // record level higher than this will be printed +format string // format configuration +timeFormat string // format for time +file string // file name for logging +out io.Writer // writer for logging +sync bool // use sync or async way to record logs +``` +The detailed description of these fields will be presented later. + +#### Logging Functions +It supports the following functions for logging. All of these functions are +thread-safe. +```go +(*Logger) Logf(level Level, format string, v ...interface{}) +(*Logger) Log(level Level, v ...interface{}) +(*Logger) Criticalf(format string, v ...interface{}) +(*Logger) Critical(v ...interface{}) +(*Logger) Fatalf(format string, v ...interface{}) +(*Logger) Fatal(v ...interface{}) +(*Logger) Errorf(format string, v ...interface{}) +(*Logger) Error(v ...interface{}) +(*Logger) Warningf(format string, v ...interface{}) +(*Logger) Warning(v ...interface{}) +(*Logger) Warnf(format string, v ...interface{}) +(*Logger) Warn(v ...interface{}) +(*Logger) Infof(format string, v ...interface{}) +(*Logger) Info(v ...interface{}) +(*Logger) Debugf(format string, v ...interface{}) +(*Logger) Debug(v ...interface{}) +(*Logger) Notsetf(format string, v ...interface{}) +(*Logger) Notset(v ...interface{}) +``` + +#### Logger Operations +The logger supports the following operations. In these functions, `SetWriter` +and `Destroy` are not thread-safe, while others are. All these functions are +running in a synchronous way. +```go +// Getter functions +(*Logger) Name() string // get name +(*Logger) TimeFormat() string // get time format +(*Logger) Level() Level // get level [this function is thread safe] +(*Logger) RecordFormat() string // get the first part of the format +(*Logger) RecordArgs() []string // get the second part of the format +(*Logger) Writer() io.Writer // get writer +(*Logger) Sync() bool // get sync or async + +// Setter functions +(*Logger) SetLevel(level Level) // set level [this function is thread safe] +(*Logger) SetWriter(out ...io.Writer) // set multiple writers + +// Other functions +(*Logger) Flush() // flush the writer +(*Logger) Destroy() // destroy the logger +``` + +#### Fields Description + +##### Name +Name field is a string, which can be written to the logging and used to +separate multiple loggers. It allows two logger having the same name. There +is not any default value for name. + +##### Logging Levels +There are these levels in logging. +```go +CRITICAL 50 +FATAL CRITICAL +ERROR 40 +WARNING 30 +WARN WARNING +INFO 20 +DEBUG 10 +NOTSET 0 +``` + +##### Record Format +The record format is described by a string, which has two parts separated by +`\n`. The first part describes the format of the log, and the second part +lists all the fields to be shown in the log. In other word, the first part is +the first parameter `format` of `fmt.Printf(format string, v ...interface{})`, +and the second part describes the second parameter `v` of it. It is not +allowed to have `\n` in the first part. The fields in the second part are +separated by comma `,`, while extra blank spaces are allowed. An example of +the format string is +```go +const BasicFormat = "%s [%6s] %30s - %s\n name,levelname,time,message" +``` +which is the pre-defined `BasicFormat` used by `BasicLogger()` and +`SimpleLogger()`. + +It supports the following fields for the second part of the format. +```go +"name" string %s // name of the logger +"seqid" uint64 %d // sequence number +"levelno" int32 %d // level number +"levelname" string %s // level name +"created" int64 %d // starting time of the logger +"nsecs" int64 %d // nanosecond of the starting time +"time" string %s // record created time +"timestamp" int64 %d // timestamp of record +"rtime" int64 %d // relative time since started +"filename" string %s // source filename of the caller +"pathname" string %s // filename with path +"module" string %s // executable filename +"lineno" int %d // line number in source code +"funcname" string %s // function name of the caller +"thread" int32 %d // thread id +"process" int %d // process id +"message" string %d // logger message +``` +The following runtime-related fields is extremely expensive and slow, please +be careful when using them. +```go +"filename" string %s // source filename of the caller +"pathname" string %s // filename with path +"lineno" int %d // line number in source code +"funcname" string %s // function name of the caller +"thread" int32 %d // thread id +``` + +There are a few pre-defined values for record format. +```go +BasicFormat = "%s [%6s] %30s - %s\n name,levelname,time,message" +RichFormat = "%s [%6s] %d %30s - %d - %s:%s:%d - %s\n name, levelname, seqid, time, thread, filename, funcname, lineno, message" +``` + +##### Time Format +We use the same time format as golang. The default time format is +```go +DefaultTimeFormat = "2006-01-02 15:04:05.999999999" // default time format +``` + +##### File Name, Writer, and Sync +The meaning of these fields are obvious. Filename is used to create writer. +We also allow the user create a writer by herself and pass it to the logger. +Sync describes whether the user would like to use synchronous or asynchronous +method to write logs. `true` value means synchronous method, and `false` value +means asynchronous way. We suggest you use asynchronous way because it causes +extremely low extra delay by the logging functions. + +## Contributors +In alphabetical order +* Cong Ding ([ccding][ccding]) +* Xiang Li ([xiangli-cmu][xiangli]) +* Zifei Tong ([5kg][5kg]) +[ccding]: //github.com/ccding +[xiangli]: //github.com/xiangli-cmu +[5kg]: //github.com/5kg + +## TODO List +1. logging server diff --git a/third_party/github.com/ccding/go-logging/example.conf b/third_party/github.com/ccding/go-logging/example.conf new file mode 100644 index 000000000..ecc9a860e --- /dev/null +++ b/third_party/github.com/ccding/go-logging/example.conf @@ -0,0 +1,3 @@ +name = example +sync = 0 + diff --git a/third_party/github.com/ccding/go-logging/example.go b/third_party/github.com/ccding/go-logging/example.go new file mode 100644 index 000000000..5d9fc6397 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/example.go @@ -0,0 +1,45 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package main + +import ( + "github.com/ccding/go-logging/logging" + "time" +) + +func main() { + logger1, _ := logging.SimpleLogger("main") + logger1.SetLevel(logging.NOTSET) + logger1.Error("this is a test from error") + logger1.Debug("this is a test from debug") + logger1.Notset("orz", time.Now().UnixNano()) + logger1.Destroy() + + logger2, _ := logging.RichLogger("main") + logger2.SetLevel(logging.DEBUG) + logger2.Error("this is a test from error") + logger2.Debug("this is a test from debug") + logger2.Notset("orz", time.Now().UnixNano()) + logger2.Destroy() + + logger3, _ := logging.ConfigLogger("example.conf") + logger3.SetLevel(logging.DEBUG) + logger3.Error("this is a test from error") + logger3.Debug("this is a test from debug") + logger3.Notset("orz", time.Now().UnixNano()) + logger3.Destroy() +} diff --git a/third_party/github.com/ccding/go-logging/logging/commands.go b/third_party/github.com/ccding/go-logging/logging/commands.go new file mode 100644 index 000000000..6cf2bb4a3 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/commands.go @@ -0,0 +1,98 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +// Logln receives log request from the client. The request includes a set of +// variables. +func (logger *Logger) Log(level Level, v ...interface{}) { + // Don't delete this calling. The calling is used to keep the same + // calldepth for all the logging functions. The calldepth is used to + // get runtime information such as line number, function name, etc. + logger.log(level, v...) +} + +// Logf receives log request from the client. The request has a string +// parameter to describe the format of output. +func (logger *Logger) Logf(level Level, format string, v ...interface{}) { + logger.logf(level, format, v...) +} + +// Other quick commands for different level + +func (logger *Logger) Critical(v ...interface{}) { + logger.log(CRITICAL, v...) +} + +func (logger *Logger) Fatal(v ...interface{}) { + logger.log(CRITICAL, v...) +} + +func (logger *Logger) Error(v ...interface{}) { + logger.log(ERROR, v...) +} + +func (logger *Logger) Warn(v ...interface{}) { + logger.log(WARNING, v...) +} + +func (logger *Logger) Warning(v ...interface{}) { + logger.log(WARNING, v...) +} + +func (logger *Logger) Info(v ...interface{}) { + logger.log(INFO, v...) +} + +func (logger *Logger) Debug(v ...interface{}) { + logger.log(DEBUG, v...) +} + +func (logger *Logger) Notset(v ...interface{}) { + logger.log(NOTSET, v...) +} + +func (logger *Logger) Criticalf(format string, v ...interface{}) { + logger.logf(CRITICAL, format, v...) +} + +func (logger *Logger) Fatalf(format string, v ...interface{}) { + logger.logf(CRITICAL, format, v...) +} + +func (logger *Logger) Errorf(format string, v ...interface{}) { + logger.logf(ERROR, format, v...) +} + +func (logger *Logger) Warnf(format string, v ...interface{}) { + logger.logf(WARNING, format, v...) +} + +func (logger *Logger) Warningf(format string, v ...interface{}) { + logger.logf(WARNING, format, v...) +} + +func (logger *Logger) Infof(format string, v ...interface{}) { + logger.logf(INFO, format, v...) +} + +func (logger *Logger) Debugf(format string, v ...interface{}) { + logger.logf(DEBUG, format, v...) +} + +func (logger *Logger) Notsetf(format string, v ...interface{}) { + logger.logf(NOTSET, format, v...) +} diff --git a/third_party/github.com/ccding/go-logging/logging/fields.go b/third_party/github.com/ccding/go-logging/logging/fields.go new file mode 100644 index 000000000..74c05b190 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/fields.go @@ -0,0 +1,236 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +import ( + "bitbucket.org/kardianos/osext" + "os" + "path" + "runtime" + "sync/atomic" + "time" +) + +// The struct for each log record +type record struct { + level Level + seqid uint64 + pathname string + filename string + module string + lineno int + funcname string + thread int + process int + message string + time time.Time +} + +// This variable maps fields in recordArgs to relavent function signatures +var fields = map[string]func(*Logger, *record) interface{}{ + "name": (*Logger).lname, // name of the logger + "seqid": (*Logger).nextSeqid, // sequence number + "levelno": (*Logger).levelno, // level number + "levelname": (*Logger).levelname, // level name + "created": (*Logger).created, // starting time of the logger + "nsecs": (*Logger).nsecs, // nanosecond of the starting time + "time": (*Logger).time, // record created time + "timestamp": (*Logger).timestamp, // timestamp of record + "rtime": (*Logger).rtime, // relative time since started + "filename": (*Logger).filename, // source filename of the caller + "pathname": (*Logger).pathname, // filename with path + "module": (*Logger).module, // executable filename + "lineno": (*Logger).lineno, // line number in source code + "funcname": (*Logger).funcname, // function name of the caller + "thread": (*Logger).thread, // thread id + "process": (*Logger).process, // process id + "message": (*Logger).message, // logger message +} + +var runtimeFields = map[string]bool{ + "name": false, + "seqid": false, + "levelno": false, + "levelname": false, + "created": false, + "nsecs": false, + "time": false, + "timestamp": false, + "rtime": false, + "filename": true, + "pathname": true, + "module": false, + "lineno": true, + "funcname": true, + "thread": true, + "process": false, + "message": false, +} + +// If it fails to get some fields with string type, these fields are set to +// errString value. +const errString = "???" + +// GetGoID returns the id of goroutine, which is defined in ./get_go_id.c +func GetGoID() int32 + +// genRuntime generates the runtime information, including pathname, function +// name, filename, line number. +func genRuntime(r *record) { + calldepth := 5 + pc, file, line, ok := runtime.Caller(calldepth) + if ok { + // Generate short function name + fname := runtime.FuncForPC(pc).Name() + fshort := fname + for i := len(fname) - 1; i > 0; i-- { + if fname[i] == '.' { + fshort = fname[i+1:] + break + } + } + + r.pathname = file + r.funcname = fshort + r.filename = path.Base(file) + r.lineno = line + } else { + r.pathname = errString + r.funcname = errString + r.filename = errString + // Here we uses -1 rather than 0, because the default value in + // golang is 0 and we should know the value is uninitialized + // or failed to get + r.lineno = -1 + } +} + +// Logger name +func (logger *Logger) lname(r *record) interface{} { + return logger.name +} + +// Next sequence number +func (logger *Logger) nextSeqid(r *record) interface{} { + if r.seqid == 0 { + r.seqid = atomic.AddUint64(&(logger.seqid), 1) + } + return r.seqid +} + +// Log level number +func (logger *Logger) levelno(r *record) interface{} { + return int32(r.level) +} + +// Log level name +func (logger *Logger) levelname(r *record) interface{} { + return levelNames[r.level] +} + +// File name of calling logger, with whole path +func (logger *Logger) pathname(r *record) interface{} { + if r.pathname == "" { + genRuntime(r) + } + return r.pathname +} + +// File name of calling logger +func (logger *Logger) filename(r *record) interface{} { + if r.filename == "" { + genRuntime(r) + } + return r.filename +} + +// module name +func (logger *Logger) module(r *record) interface{} { + module, _ := osext.Executable() + return path.Base(module) +} + +// Line number +func (logger *Logger) lineno(r *record) interface{} { + if r.lineno == 0 { + genRuntime(r) + } + return r.lineno +} + +// Function name +func (logger *Logger) funcname(r *record) interface{} { + if r.funcname == "" { + genRuntime(r) + } + return r.funcname +} + +// Timestamp of starting time +func (logger *Logger) created(r *record) interface{} { + return logger.startTime.UnixNano() +} + +// RFC3339Nano time +func (logger *Logger) time(r *record) interface{} { + if r.time.IsZero() { + r.time = time.Now() + } + return r.time.Format(logger.timeFormat) +} + +// Nanosecond of starting time +func (logger *Logger) nsecs(r *record) interface{} { + return logger.startTime.Nanosecond() +} + +// Nanosecond timestamp +func (logger *Logger) timestamp(r *record) interface{} { + if r.time.IsZero() { + r.time = time.Now() + } + return r.time.UnixNano() +} + +// Nanoseconds since logger created +func (logger *Logger) rtime(r *record) interface{} { + if r.time.IsZero() { + r.time = time.Now() + } + return r.time.Sub(logger.startTime).Nanoseconds() +} + +// Thread ID +func (logger *Logger) thread(r *record) interface{} { + if r.thread == 0 { + r.thread = int(GetGoID()) + } + return r.thread +} + +// Process ID +func (logger *Logger) process(r *record) interface{} { + if r.process == 0 { + r.process = os.Getpid() + } + return r.process +} + +// The log message +func (logger *Logger) message(r *record) interface{} { + return r.message +} diff --git a/third_party/github.com/ccding/go-logging/logging/fields_test.go b/third_party/github.com/ccding/go-logging/logging/fields_test.go new file mode 100644 index 000000000..8433850d9 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/fields_test.go @@ -0,0 +1,60 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +import ( + "fmt" + "strconv" + "testing" +) + +func empty() { +} + +func TestGetGoID(t *testing.T) { + for i := 0; i < 1000; i++ { + goid := int(GetGoID()) + go empty() + goid2 := int(GetGoID()) + if goid != goid2 { + t.Errorf("%v, %v\n", goid, goid2) + } + } +} + +func TestSeqid(t *testing.T) { + logger, _ := BasicLogger("test") + for i := 0; i < 1000; i++ { + r := new(record) + name := strconv.Itoa(i + 1) + seq := logger.nextSeqid(r) + if fmt.Sprintf("%d", seq) != name { + t.Errorf("%v, %v\n", seq, name) + } + } + logger.Destroy() +} + +func TestName(t *testing.T) { + name := "test" + logger, _ := BasicLogger(name) + r := new(record) + if logger.lname(r) != name { + t.Errorf("%v, %v\n", logger.lname(r), name) + } + logger.Destroy() +} diff --git a/third_party/github.com/ccding/go-logging/logging/formater.go b/third_party/github.com/ccding/go-logging/logging/formater.go new file mode 100644 index 000000000..c704d57ae --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/formater.go @@ -0,0 +1,62 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +import ( + "errors" + "fmt" + "strings" +) + +// pre-defined formats +const ( + BasicFormat = "%s [%6s] %30s - %s\n name,levelname,time,message" + RichFormat = "%s [%6s] %d %30s - %d - %s:%s:%d - %s\n name, levelname, seqid, time, thread, filename, funcname, lineno, message" +) + +// genLog generates log string from the format setting. +func (logger *Logger) genLog(level Level, message string) string { + fs := make([]interface{}, len(logger.recordArgs)) + r := new(record) + r.message = message + r.level = level + for k, v := range logger.recordArgs { + fs[k] = fields[v](logger, r) + } + return fmt.Sprintf(logger.recordFormat, fs...) +} + +// parseFormat checks the legality of format and parses it to recordFormat and recordArgs +func (logger *Logger) parseFormat(format string) error { + logger.runtime = false + fts := strings.Split(format, "\n") + if len(fts) != 2 { + return errors.New("logging format error") + } + logger.recordFormat = fts[0] + logger.recordArgs = strings.Split(fts[1], ",") + for k, v := range logger.recordArgs { + tv := strings.TrimSpace(v) + _, ok := fields[tv] + if ok == false { + return errors.New("logging format error") + } + logger.recordArgs[k] = tv + logger.runtime = logger.runtime || runtimeFields[tv] + } + return nil +} diff --git a/third_party/github.com/ccding/go-logging/logging/get_go_id.c b/third_party/github.com/ccding/go-logging/logging/get_go_id.c new file mode 100644 index 000000000..400848cf9 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/get_go_id.c @@ -0,0 +1,25 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +// This file defines GetGoId function, which is used to get the id of the +// current goroutine. More details about this function are availeble in the +// runtime.c file of golang source code. +#include + +void ·GetGoID(int32 ret) { + ret = g->goid; + USED(&ret); +} diff --git a/third_party/github.com/ccding/go-logging/logging/level.go b/third_party/github.com/ccding/go-logging/logging/level.go new file mode 100644 index 000000000..e640fa626 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/level.go @@ -0,0 +1,68 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +// Level is the type of level. +type Level int32 + +// Values of level +const ( + CRITICAL Level = 50 + FATAL Level = CRITICAL + ERROR Level = 40 + WARNING Level = 30 + WARN Level = WARNING + INFO Level = 20 + DEBUG Level = 10 + NOTSET Level = 0 +) + +// The mapping from level to level name +var levelNames = map[Level]string{ + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +// The mapping from level name to level +var levelValues = map[string]Level{ + "CRITICAL": CRITICAL, + "ERROR": ERROR, + "WARN": WARNING, + "WARNING": WARNING, + "INFO": INFO, + "DEBUG": DEBUG, + "NOTSET": NOTSET, +} + +// String function casts level value to string +func (level *Level) String() string { + return levelNames[*level] +} + +// GetLevelName lets users be able to get level name from level value. +func GetLevelName(levelValue Level) string { + return levelNames[levelValue] +} + +// GetLevelValue lets users be able to get level value from level name. +func GetLevelValue(levelName string) Level { + return levelValues[levelName] +} diff --git a/third_party/github.com/ccding/go-logging/logging/logging.go b/third_party/github.com/ccding/go-logging/logging/logging.go new file mode 100644 index 000000000..1981c9a61 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/logging.go @@ -0,0 +1,260 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding + +// Package logging implements log library for other applications. It provides +// functions Debug, Info, Warning, Error, Critical, and formatting version +// Logf. +// +// Example: +// +// logger := logging.SimpleLogger("main") +// logger.SetLevel(logging.WARNING) +// logger.Error("test for error") +// logger.Warning("test for warning", "second parameter") +// logger.Debug("test for debug") +// +package logging + +import ( + "github.com/ccding/go-config-reader/config" + "io" + "os" + "strconv" + "sync" + "sync/atomic" + "time" +) + +// Pre-defined formats +const ( + DefaultFileName = "logging.log" // default logging filename + DefaultConfigFile = "logging.conf" // default logging configuration file + DefaultTimeFormat = "2006-01-02 15:04:05.999999999" // defaulttime format + bufSize = 1000 // buffer size for writer + queueSize = 10000 // chan queue size in async logging + reqSize = 10000 // chan queue size in async logging +) + +// Logger is the logging struct. +type Logger struct { + + // Be careful of the alignment issue of the variable seqid because it + // uses the sync/atomic.AddUint64() operation. If the alignment is + // wrong, it will cause a panic. To solve the alignment issue in an + // easy way, we put seqid to the beginning of the structure. + // seqid is only visiable internally. + seqid uint64 // last used sequence number in record + + // These variables can be configured by users. + name string // logger name + level Level // record level higher than this will be printed + recordFormat string // format of the record + recordArgs []string // arguments to be used in the recordFormat + out io.Writer // writer + sync bool // use sync or async way to record logs + timeFormat string // format for time + + // These variables are visible to users. + startTime time.Time // start time of the logger + + // Internally used variables, which don't have get and set functions. + wlock sync.Mutex // writer lock + queue chan string // queue used in async logging + request chan request // queue used in non-runtime logging + flush chan bool // flush signal for the watcher to write + quit chan bool // quit signal for the watcher to quit + fd *os.File // file handler, used to close the file on destroy + runtime bool // with runtime operation or not +} + +// SimpleLogger creates a new logger with simple configuration. +func SimpleLogger(name string) (*Logger, error) { + return createLogger(name, WARNING, BasicFormat, DefaultTimeFormat, os.Stdout, false) +} + +// BasicLogger creates a new logger with basic configuration. +func BasicLogger(name string) (*Logger, error) { + return FileLogger(name, WARNING, BasicFormat, DefaultTimeFormat, DefaultFileName, false) +} + +// RichLogger creates a new logger with simple configuration. +func RichLogger(name string) (*Logger, error) { + return FileLogger(name, NOTSET, RichFormat, DefaultTimeFormat, DefaultFileName, false) +} + +// FileLogger creates a new logger with file output. +func FileLogger(name string, level Level, format string, timeFormat string, file string, sync bool) (*Logger, error) { + out, err := os.Create(file) + if err != nil { + return new(Logger), err + } + logger, err := createLogger(name, level, format, timeFormat, out, sync) + if err == nil { + logger.fd = out + } + return logger, err +} + +// WriterLogger creates a new logger with a writer +func WriterLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) { + return createLogger(name, level, format, timeFormat, out, sync) +} + +// WriterLogger creates a new logger from a configuration file +func ConfigLogger(filename string) (*Logger, error) { + conf, err := config.Read(filename) + if err != nil { + return new(Logger), err + } + ok := true + name, ok := conf["name"] + if !ok { + name = "" + } + slevel, ok := conf["level"] + if !ok { + slevel = "0" + } + l, err := strconv.Atoi(slevel) + if err != nil { + return new(Logger), err + } + level := Level(l) + format, ok := conf["format"] + if !ok { + format = BasicFormat + } + timeFormat, ok := conf["timeFormat"] + if !ok { + timeFormat = DefaultTimeFormat + } + ssync, ok := conf["sync"] + if !ok { + ssync = "0" + } + file, ok := conf["file"] + if !ok { + file = DefaultFileName + } + sync := true + if ssync == "0" { + sync = false + } else if ssync == "1" { + sync = true + } else { + return new(Logger), err + } + return FileLogger(name, level, format, timeFormat, file, sync) +} + +// createLogger create a new logger +func createLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) { + logger := new(Logger) + + err := logger.parseFormat(format) + if err != nil { + return logger, err + } + + // asign values to logger + logger.name = name + logger.level = level + logger.out = out + logger.seqid = 0 + logger.sync = sync + logger.queue = make(chan string, queueSize) + logger.request = make(chan request, reqSize) + logger.flush = make(chan bool) + logger.quit = make(chan bool) + logger.startTime = time.Now() + logger.fd = nil + logger.timeFormat = timeFormat + + // start watcher to write logs if it is async or no runtime field + if !logger.sync { + go logger.watcher() + } + + return logger, nil +} + +// Destroy sends quit signal to watcher and releases all the resources. +func (logger *Logger) Destroy() { + if !logger.sync { + // quit watcher + logger.quit <- true + // wait for watcher quit + <-logger.quit + } + // clean up + if logger.fd != nil { + logger.fd.Close() + } +} + +// Flush the writer +func (logger *Logger) Flush() { + if !logger.sync { + // send flush signal + logger.flush <- true + // wait for flush finish + <-logger.flush + } +} + +// Getter functions + +func (logger *Logger) Name() string { + return logger.name +} + +func (logger *Logger) StartTime() int64 { + return logger.startTime.UnixNano() +} + +func (logger *Logger) TimeFormat() string { + return logger.timeFormat +} + +func (logger *Logger) Level() Level { + return Level(atomic.LoadInt32((*int32)(&logger.level))) +} + +func (logger *Logger) RecordFormat() string { + return logger.recordFormat +} + +func (logger *Logger) RecordArgs() []string { + return logger.recordArgs +} + +func (logger *Logger) Writer() io.Writer { + return logger.out +} + +func (logger *Logger) Sync() bool { + return logger.sync +} + +// Setter functions + +func (logger *Logger) SetLevel(level Level) { + atomic.StoreInt32((*int32)(&logger.level), int32(level)) +} + +func (logger *Logger) SetWriter(out ...io.Writer) { + logger.out = io.MultiWriter(out...) +} diff --git a/third_party/github.com/ccding/go-logging/logging/logging_test.go b/third_party/github.com/ccding/go-logging/logging/logging_test.go new file mode 100644 index 000000000..b6e0fa502 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/logging_test.go @@ -0,0 +1,71 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +import ( + "fmt" + "os" + "testing" +) + +func BenchmarkSync(b *testing.B) { + logger, _ := RichLogger("main") + logger.SetLevel(NOTSET) + for i := 0; i < b.N; i++ { + logger.Error("this is a test from error") + } + logger.Flush() + logger.Destroy() +} + +func BenchmarkAsync(b *testing.B) { + logger, _ := RichLogger("main") + logger.SetLevel(NOTSET) + for i := 0; i < b.N; i++ { + logger.Error("this is a test from error") + } + logger.Flush() + logger.Destroy() +} + +func BenchmarkBasicSync(b *testing.B) { + logger, _ := BasicLogger("main") + logger.SetLevel(NOTSET) + for i := 0; i < b.N; i++ { + logger.Error("this is a test from error") + } + logger.Flush() + logger.Destroy() +} + +func BenchmarkBasicAsync(b *testing.B) { + logger, _ := BasicLogger("main") + logger.SetLevel(NOTSET) + for i := 0; i < b.N; i++ { + logger.Error("this is a test from error") + } + logger.Flush() + logger.Destroy() +} + +func BenchmarkPrintln(b *testing.B) { + out, _ := os.Create("logging.log") + for i := 0; i < b.N; i++ { + fmt.Fprintln(out, "this is a test from error") + } + out.Close() +} diff --git a/third_party/github.com/ccding/go-logging/logging/request.go b/third_party/github.com/ccding/go-logging/logging/request.go new file mode 100644 index 000000000..e823fa719 --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/request.go @@ -0,0 +1,24 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +// request struct stores the logger request +type request struct { + level Level + format string + v []interface{} +} diff --git a/third_party/github.com/ccding/go-logging/logging/writer.go b/third_party/github.com/ccding/go-logging/logging/writer.go new file mode 100644 index 000000000..12d17901a --- /dev/null +++ b/third_party/github.com/ccding/go-logging/logging/writer.go @@ -0,0 +1,130 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding +// +package logging + +import ( + "bytes" + "fmt" + "sync/atomic" + "time" +) + +// watcher watches the logger.queue channel, and writes the logs to output +func (logger *Logger) watcher() { + var buf bytes.Buffer + for { + timeout := time.After(time.Second / 10) + + for i := 0; i < bufSize; i++ { + select { + case msg := <-logger.queue: + fmt.Fprintln(&buf, msg) + case req := <-logger.request: + logger.flushReq(&buf, &req) + case <-timeout: + i = bufSize + case <-logger.flush: + logger.flushBuf(&buf) + logger.flush <- true + i = bufSize + case <-logger.quit: + // If quit signal received, cleans the channel + // and writes all of them to io.Writer. + for { + select { + case msg := <-logger.queue: + fmt.Fprintln(&buf, msg) + case req := <-logger.request: + logger.flushReq(&buf, &req) + case <-logger.flush: + // do nothing + default: + logger.flushBuf(&buf) + logger.quit <- true + return + } + } + } + } + logger.flushBuf(&buf) + } +} + +// flushBuf flushes the content of buffer to out and reset the buffer +func (logger *Logger) flushBuf(b *bytes.Buffer) { + if len(b.Bytes()) > 0 { + logger.out.Write(b.Bytes()) + b.Reset() + } +} + +// flushReq handles the request and writes the result to writer +func (logger *Logger) flushReq(b *bytes.Buffer, req *request) { + if req.format == "" { + msg := fmt.Sprint(req.v...) + msg = logger.genLog(req.level, msg) + fmt.Fprintln(b, msg) + } else { + msg := fmt.Sprintf(req.format, req.v...) + msg = logger.genLog(req.level, msg) + fmt.Fprintln(b, msg) + } +} + +// flushMsg is to print log to file, stdout, or others. +func (logger *Logger) flushMsg(message string) { + if logger.sync { + logger.wlock.Lock() + defer logger.wlock.Unlock() + fmt.Fprintln(logger.out, message) + } else { + logger.queue <- message + } +} + +// log records log v... with level `level'. +func (logger *Logger) log(level Level, v ...interface{}) { + if int32(level) >= atomic.LoadInt32((*int32)(&logger.level)) { + if logger.runtime || logger.sync { + message := fmt.Sprint(v...) + message = logger.genLog(level, message) + logger.flushMsg(message) + } else { + r := new(request) + r.level = level + r.v = v + logger.request <- *r + } + } +} + +// logf records log v... with level `level'. +func (logger *Logger) logf(level Level, format string, v ...interface{}) { + if int32(level) >= atomic.LoadInt32((*int32)(&logger.level)) { + if logger.runtime || logger.sync { + message := fmt.Sprintf(format, v...) + message = logger.genLog(level, message) + logger.flushMsg(message) + } else { + r := new(request) + r.level = level + r.format = format + r.v = v + logger.request <- *r + } + } +}