-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Simple sync log. #327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Simple sync log. #327
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ad435dc
Add SyncWriter and SyncLogger.
ChrisHines 22fe74f
Run more tests in parallel.
ChrisHines 51ae681
Improve log.testConcurrency to check errors and control total event c…
ChrisHines a9b82c9
Unify package docs.
ChrisHines d235bef
Update package docs and examples.
ChrisHines 9de3cf1
Fix two documentation typos.
ChrisHines File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing doc comment. Thank you.