From e8325711b39f2f685c557652aae8e45666ee746e Mon Sep 17 00:00:00 2001 From: Keepers Date: Thu, 25 May 2023 00:28:40 -0600 Subject: [PATCH] update logging standards doc (#3497) #### Type of change - [x] :world_map: Documentation --- src/pkg/logger/example_logger_test.go | 46 +++++++++++++++++++++------ 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/pkg/logger/example_logger_test.go b/src/pkg/logger/example_logger_test.go index b71cddf11..b141efecf 100644 --- a/src/pkg/logger/example_logger_test.go +++ b/src/pkg/logger/example_logger_test.go @@ -6,6 +6,7 @@ import ( "github.com/alcionai/clues" "github.com/alcionai/corso/src/internal/connector" + "github.com/alcionai/corso/src/internal/connector/graph" "github.com/alcionai/corso/src/pkg/logger" "github.com/alcionai/corso/src/pkg/path" ) @@ -62,7 +63,8 @@ func Example_seed() { func Example_logger_standards() { log := logger.Ctx(context.Background()) - // 1. Keep messages short. Lowercase text, no ending punctuation. + // 1. Keep messages short. When possible, messages should state the current action. + // Lowercase text, no ending punctuation. // This ensures logs are easy to scan, and simple to grok. // // preferred @@ -70,7 +72,15 @@ func Example_logger_standards() { // avoid log.Info("Getting one item from the service so that we can send it through the item feed.") - // 2. Do not fmt values into the message. Use With() or -w() to add structured data. + // 2. Avoid statements like "unable to...", "failed to..", or "error when...". + // Error level logs automatically imply a failure to do the action. + // + // preferred + log.With("err", err).Error("connecting to repo") + // avoid + log.With("err", err).Error("unable to connect to repo") + + // 3. Do not fmt values into the message. Use With() or -w() to add structured data. // By keeping dynamic data in a structured format, we maximize log readability, // and make logs very easy to search or filter in bulk, and very easy to control pii. // @@ -80,7 +90,7 @@ func Example_logger_standards() { // avoid log.Errorf("getting item %s: %v", itemID, err) - // 3. Give data keys reasonable namespaces. Use snake_case. + // 4. Give data keys reasonable namespaces. Use snake_case. // Overly generic keys can collide unexpectedly. // // preferred @@ -98,14 +108,14 @@ func Example_logger_standards() { // avoid log.With("err", err).Warn("getting item") - // 4. Avoid Panic/Fatal-level logging. Prefer Error. + // 5. Avoid Panic/Fatal-level logging. Prefer Error. // Panic and Fatal logging can crash the application without // flushing buffered logs and finishing out other telemetry. // // preferred - log.With("err", err).Error("unable to connect") + log.With("err", err).Error("connecting to repo") // avoid - log.With("err", err).Panic("unable to connecct") + log.With("err", err).Panic("connecting to repo") } // ExampleLoggerCluesStandards reviews code standards around using the Clues package while logging. @@ -124,7 +134,14 @@ func Example_logger_clues_standards() { ctx = clues.Add(ctx, "item_id", itemID) logger.Ctx(ctx).With(clues.In(ctx).Slice()...).Info("getting item") - // 2. Always extract structured data from errors. + // 2. The last func to handle a context must add the clues to the error. + // + // preferred + err := clues.Wrap(err, "reason").WithClues(ctx) + // this dereference added for linter happiness + _ = err + + // 3. Always extract structured data from errors. // // preferred log.With("error", err).Errorw("getting item", clues.InErr(err).Slice()...) @@ -153,7 +170,15 @@ func Example_logger_clues_standards() { // Ex: clues.Hide(userName). This will hash the value according to // the user's hash algorithm configuration. // - // Third: structs that comply with clues.Concealer. The Concealer + // Third: managed string concealers. Certain values have common + // format and content, but appear commonly in the code as strings. + // Examples include URLs and kopia repository paths. These values + // may have a concealer built specifically for them to maximize the + // data we can view when debugging, instead of hashing the complete + // string. See graph/middleware.go LoggableURL{} and path/elements.go + // LoggableDir{}. + // + // Fourth: structs that comply with clues.Concealer. The Concealer // interface requires a struct to comply with Conceal() (for cases // where the struct is handed to a clues aggregator directly), and // fmt's Format(state, verb), where the assumption is the standard @@ -166,7 +191,8 @@ func Example_logger_clues_standards() { "resource_type", connector.Users, // string containing sensitive info, wrap with Hide() "user_name", clues.Hide("your_user_name@microsoft.example"), + // string partially concealed by a managed concealer. + "request_url", graph.LoggableURL("https://corsobackup.io"), // a concealer-compliant struct, safe to add plainly - "storage_path", itemPath, - ) + "storage_path", itemPath) }