Browse Source

bump(github.com/ccding/go-logging): d4e747a24b2af160872a886a430a16ac65f76456

Brandon Philips 12 years ago
parent
commit
7992171974

+ 22 - 0
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

+ 191 - 0
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.

+ 226 - 0
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

+ 3 - 0
third_party/github.com/ccding/go-logging/example.conf

@@ -0,0 +1,3 @@
+name = example
+sync = 0
+

+ 45 - 0
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 <dinggnu@gmail.com>
+//
+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()
+}

+ 98 - 0
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 <dinggnu@gmail.com>
+//
+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...)
+}

+ 236 - 0
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 <dinggnu@gmail.com>
+//
+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
+}

+ 60 - 0
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 <dinggnu@gmail.com>
+//
+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()
+}

+ 62 - 0
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 <dinggnu@gmail.com>
+//
+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
+}

+ 25 - 0
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 <dinggnu@gmail.com>
+//
+// 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 <runtime.h>
+
+void ·GetGoID(int32 ret) {
+	ret = g->goid;
+	USED(&ret);
+}

+ 68 - 0
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 <dinggnu@gmail.com>
+//
+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]
+}

+ 260 - 0
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 <dinggnu@gmail.com>
+
+// 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...)
+}

+ 71 - 0
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 <dinggnu@gmail.com>
+//
+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()
+}

+ 24 - 0
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 <dinggnu@gmail.com>
+//
+package logging
+
+// request struct stores the logger request
+type request struct {
+	level  Level
+	format string
+	v      []interface{}
+}

+ 130 - 0
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 <dinggnu@gmail.com>
+//
+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
+		}
+	}
+}