-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #327 from go-kit/simple-sync-log
Simple sync log.
- Loading branch information
Showing
14 changed files
with
381 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,40 @@ | ||
package log_test | ||
|
||
import ( | ||
"strconv" | ||
"sync" | ||
"math" | ||
"testing" | ||
|
||
"github.com/go-kit/kit/log" | ||
) | ||
|
||
// These test are designed to be run with the race detector. | ||
|
||
func testConcurrency(t *testing.T, logger log.Logger) { | ||
for _, n := range []int{10, 100, 500} { | ||
wg := sync.WaitGroup{} | ||
wg.Add(n) | ||
for i := 0; i < n; i++ { | ||
go func() { spam(logger); wg.Done() }() | ||
func testConcurrency(t *testing.T, logger log.Logger, total int) { | ||
n := int(math.Sqrt(float64(total))) | ||
share := total / n | ||
|
||
errC := make(chan error, n) | ||
|
||
for i := 0; i < n; i++ { | ||
go func() { | ||
errC <- spam(logger, share) | ||
}() | ||
} | ||
|
||
for i := 0; i < n; i++ { | ||
err := <-errC | ||
if err != nil { | ||
t.Fatalf("concurrent logging error: %v", err) | ||
} | ||
wg.Wait() | ||
} | ||
} | ||
|
||
func spam(logger log.Logger) { | ||
for i := 0; i < 100; i++ { | ||
logger.Log("key", strconv.FormatInt(int64(i), 10)) | ||
func spam(logger log.Logger, count int) error { | ||
for i := 0; i < count; i++ { | ||
err := logger.Log("key", i) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,93 @@ | ||
// Package log provides a structured logger. | ||
// | ||
// Services produce logs to be consumed later, either by humans or machines. | ||
// Humans might be interested in debugging errors, or tracing specific requests. | ||
// Machines might be interested in counting interesting events, or aggregating | ||
// information for offline processing. In both cases, it's important that the | ||
// log messages be structured and actionable. Package log is designed to | ||
// encourage both of these best practices. | ||
// Structured logging produces logs easily consumed later by humans or | ||
// machines. Humans might be interested in debugging errors, or tracing | ||
// specific requests. Machines might be interested in counting interesting | ||
// events, or aggregating information for off-line processing. In both cases, | ||
// it is important that the log messages are structured and actionable. | ||
// Package log is designed to encourage both of these best practices. | ||
// | ||
// Basic Usage | ||
// | ||
// The fundamental interface is Logger. Loggers create log events from | ||
// key/value data. The Logger interface has a single method, Log, which | ||
// accepts a sequence of alternating key/value pairs, which this package names | ||
// keyvals. | ||
// | ||
// type Logger interface { | ||
// Log(keyvals ...interface{}) error | ||
// } | ||
// | ||
// Here is an example of a function using a Logger to create log events. | ||
// | ||
// func RunTask(task Task, logger log.Logger) string { | ||
// logger.Log("taskID", task.ID, "event", "starting task") | ||
// ... | ||
// logger.Log("taskID", task.ID, "event", "task complete") | ||
// } | ||
// | ||
// The keys in the above example are "taskID" and "event". The values are | ||
// task.ID, "starting task", and "task complete". Every key is followed | ||
// immediately by its value. | ||
// | ||
// Keys are usually plain strings. Values may be any type that has a sensible | ||
// encoding in the chosen log format. With structured logging it is a good | ||
// idea to log simple values without formatting them. This practice allows | ||
// the chosen logger to encode values in the most appropriate way. | ||
// | ||
// Log Context | ||
// | ||
// A log context stores keyvals that it includes in all log events. Building | ||
// appropriate log contexts reduces repetition and aids consistency in the | ||
// resulting log output. We can use a context to improve the RunTask example. | ||
// | ||
// func RunTask(task Task, logger log.Logger) string { | ||
// logger = log.NewContext(logger).With("taskID", task.ID) | ||
// logger.Log("event", "starting task") | ||
// ... | ||
// taskHelper(task.Cmd, logger) | ||
// ... | ||
// logger.Log("event", "task complete") | ||
// } | ||
// | ||
// The improved version emits the same log events as the original for the | ||
// first and last calls to Log. The call to taskHelper highlights that a | ||
// context may be passed as a logger to other functions. Each log event | ||
// created by the called function will include the task.ID even though the | ||
// function does not have access to that value. Using log contexts this way | ||
// simplifies producing log output that enables tracing the life cycle of | ||
// individual tasks. (See the Context example for the full code of the | ||
// above snippet.) | ||
// | ||
// Dynamic Context Values | ||
// | ||
// A Valuer function stored in a log context generates a new value each time | ||
// the context logs an event. The Valuer example demonstrates how this | ||
// feature works. | ||
// | ||
// Valuers provide the basis for consistently logging timestamps and source | ||
// code location. The log package defines several valuers for that purpose. | ||
// See Timestamp, DefaultTimestamp, DefaultTimestampUTC, Caller, and | ||
// DefaultCaller. A common logger initialization sequence that ensures all log | ||
// entries contain a timestamp and source location looks like this: | ||
// | ||
// logger := log.NewLogfmtLogger(log.SyncWriter(os.Stdout)) | ||
// logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) | ||
// | ||
// Concurrent Safety | ||
// | ||
// Applications with multiple goroutines want each log event written to the | ||
// same logger to remain separate from other log events. Package log provides | ||
// two simple solutions for concurrent safe logging. | ||
// | ||
// NewSyncWriter wraps an io.Writer and serializes each call to its Write | ||
// method. Using a SyncWriter has the benefit that the smallest practical | ||
// portion of the logging logic is performed within a mutex, but it requires | ||
// the formatting Logger to make only one call to Write per log event. | ||
// | ||
// NewSyncLogger wraps any Logger and serializes each call to its Log method. | ||
// Using a SyncLogger has the benefit that it guarantees each log event is | ||
// handled atomically within the wrapped logger, but it typically serializes | ||
// both the formatting and output logic. Use a SyncLogger if the formatting | ||
// logger may perform multiple writes per log event. | ||
package log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.