diary

package module
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 28, 2023 License: MIT Imports: 10 Imported by: 5

README

Diary

Logging Checklist [ pdf ]

10 Commandments of Logging “Masterzen”
  • 1. Thou shalt not write log by yourself

    • Make use of syslog or similar systems as they handle auto-ration and more.
  • 2. Thou shalt log at the proper level

    • TRACE track code routines.
    • DEBUG activated during troubleshooting for debugging.
    • INFO user-driven or system specific actions.
    • NOTICE notable events that are not errors (default level for prod), always add context.
    • WARN events that could result in error, e.g low disk space, always add context.
    • ERROR for all errors, always add context.
    • FATAL signifies the end of a program (exit program), always add context.
  • 3. Honor thy log category

    • The category allows classification of the log message. E.g. my.service.api.
    • Log categories are hierarchical to allow inherited behaviours, rules and filters.
  • 4. Thou shalt write meaningful logs

    • Treat logging as if there is no access to the program source-code.
    • Log should not depend on previous log for context as it may not be there (async).
  • 5. Thy log shalt be written in English

    • English is an internationally recognized language.
    • English is a better suited technical language.
    • English can be written in ASCII characters (stays the same over UTF-8, Unicode, etc).
  • 6. Thou shalt log with context

    • Treat logging as if there is no access to the program source-code.
    • Log messages without context are just noise.
    • Ensure that at least the local scope of variables are included in the log context.
  • 7. Thou shalt log in machine parsable format

    • Text logs are good for humans but very poor for machines.
    • Use a simple international standard format, like JSON.
    • Simplifies automation processing for alerting/auditing.
    • Log parsers require less processing of messages.
    • Log search engine indexing becomes straightforward.
  • 8. Thou shalt not log too much or too little

    • Too much logging generates too much clutter (time consuming to browse).
    • Too little logging leads to troubleshooting problems (not enough context).
    • Log more than enough in dev, then tighten it up before shipping to prod.
  • 9. Thou shalt think to the reader

    • The whole purpose of logging is so that someone will read it one day.
    • Readers deserve consistency, so stick to standards like RFC3339 (datetime).
    • Log parsers are readers too, so ensure consistency of log format/dictionary.
  • 10. Thou shalt not log only for troubleshooting

    • Auditing management/legal events, describe what users of the system are doing.
    • Profiling logs are time stamped this allows us to infer performance metrics.
    • Statistics compute user behaviours, e.g. alert when too many errors detected in a row.
References

Basic Usage

Installation
go get github.com/go-diary/diary
Create page
package main

import (
    "github.com/go-diary/diary"
)

func main() {
	instance := diary.Dear("uprate", "go-diary", "diary", diary.M{}, "git@github.com:go-diary/diary.git", "084c59f", []string{}, diary.M{}, diary.LevelTrace, diary.HumanReadableHandler)
    instance.Page(-1, 1000, true, "main", diary.M{}, "", "", nil, func(p diary.Page) {
        x := 100
        p.Debug("x", x)
    })
}
Load Page
package main

import (
	"github.com/go-diary/diary"
	"sync"
)

var channel = make(chan []byte)
var instance diary.IDiary

func main() {
	group := sync.WaitGroup{}
	go func() {
		group.Add(1)
		defer group.Done()

		routine()
	}()

	instance = diary.Dear("uprate", "go-diary", "diary", diary.M{}, "git@github.com:go-diary/diary.git", "084c59f", []string{}, diary.M{}, diary.LevelTrace, diary.HumanReadableHandler)
	instance.Page(-1, 1000, true, "main", diary.M{}, "", "", nil, func(p diary.IPage) {
		x := 100
		p.Debug("x", x)
		channel <- p.ToJson()
	})

	group.Wait()
}

func routine() {
	select {
	case data := <-channel:
		instance.Load(data, "routine", func(p diary.IPage) {
			y := 200
			p.Debug("y", y)
		})
		break
	}
}
NOTES
  • Use git config --get remote.origin.url to get repository URL using script.
  • Use git rev-parse --short HEAD to get short commit has using script.
License

This project is licensed under the MIT license. See the LICENSE file for more info.

Documentation

Index

Constants

View Source
const (
	LevelTrace   = 0
	LevelDebug   = 1
	LevelInfo    = 2
	LevelNotice  = 3
	LevelWarning = 4
	LevelError   = 5
	LevelFatal   = 6
	LevelAudit   = 7
)
View Source
const (
	TextLevelTrace      = "trace"
	TextLevelTraceEnter = "enter"
	TextLevelTraceExit  = "exit"
	TextLevelDebug      = "debug"
	TextLevelInfo       = "info"
	TextLevelNotice     = "notice"
	TextLevelWarning    = "warning"
	TextLevelError      = "error"
	TextLevelFatal      = "fatal"
	TextLevelAudit      = "audit"
)

Variables

Functions

func ConvertFromTextLevel

func ConvertFromTextLevel(value string) int

func DefaultHandler

func DefaultHandler(log Log)

func HumanReadableHandler

func HumanReadableHandler(log Log)

func IsValidLevel

func IsValidLevel(value int) bool

Types

type Auth

type Auth struct {
	Type       string `json:"type"`
	Identifier string `json:"identifier"`
	Meta       M      `json:"meta"`
}

A public struct to encapsulate the auth details for a log entry

type Chain

type Chain struct {
	Id   string `json:"id"`
	Meta M      `json:"meta"`
	Auth Auth   `json:"auth"`
}

A public struct to encapsulate the chain details for a log entry

type Commit

type Commit struct {
	Repository string   `json:"repository"`
	Hash       string   `json:"hash"`
	Tags       []string `json:"tags"`
	Meta       M        `json:"meta"`
}

A public struct to encapsulate the commit details for a log entry

type H

type H func(log Log)

A package shorthand for a handler function

type IDiary

type IDiary interface {
	// Page returns a diary.Page interface instance for consumption
	// In a page scope all logs will be linked to the same page identifier
	// This allows us to trace the entire page chain easily for troubleshooting and profiling
	//
	// - level: The default level to log at [NOTE: If -1 will inherit from diary instance]
	// - sample: A per second count indicating how frequently traces should be sampled, only applicable if level is higher than DEBUG [NOTE: if value is less than zero then will sample all traces]
	// - catch: A flag indicating if the scope should automatically catch and return errors. [NOTE: If set to true panics will be caught and returned as an error.]
	// - category: The shorthand code used to identify the given workflow category [NOTE: Categories will be concatenated by dot-nation: "main.sub1.sub2.sub3".]
	// - authType: The shorthand code for the type of auth account (may be empty)
	// - authIdentifier: The identifier, which can be anything, used to identify the given auth account (may be empty) [WARNING: Don't ever log personal data without first encrypting or salt-hashing the data.]
	// - authMeta: Can contain any other additional data that you may require on logs for troubleshooting (may be empty) [WARNING: Don't ever log personal data without first encrypting or salt-hashing the data.]
	Page(level int, sample int, catch bool, category string, pageMeta M, authType, authIdentifier string, authMeta M, scope S)

	// Page returns a diary.Page interface instance for consumption
	// In a page scope all logs will be linked to the same page identifier
	// This allows us to trace the entire page chain easily for troubleshooting and profiling
	//
	// - level: The default level to log at [NOTE: If -1 will inherit from diary instance]
	// - sample: A per second count indicating how frequently traces should be sampled, only applicable if level is higher than DEBUG [NOTE: if value is less than zero then will sample all traces]
	// - catch: A flag indicating if the scope should automatically catch and return errors. [NOTE: If set to true panics will be caught and returned as an error.]
	// - category: The shorthand code used to identify the given workflow category [NOTE: Categories will be concatenated by dot-nation: "main.sub1.sub2.sub3".]
	// - authType: The shorthand code for the type of auth account (may be empty)
	// - authIdentifier: The identifier, which can be anything, used to identify the given auth account (may be empty) [WARNING: Don't ever log personal data without first encrypting or salt-hashing the data.]
	// - authMeta: Can contain any other additional data that you may require on logs for troubleshooting (may be empty) [WARNING: Don't ever log personal data without first encrypting or salt-hashing the data.]
	PageX(level int, sample int, catch bool, category string, pageMeta M, authType, authIdentifier string, authMeta M, scope S) error

	// Load a page using the JSON definition to chain multiple logs together when crossing micro-service boundaries
	Load(data []byte, category string, scope S)

	// Load a page using the JSON definition to chain multiple logs together when crossing micro-service boundaries
	LoadX(data []byte, category string, scope S) error
}

An definition of the public functions for a diary instance

func Dear

func Dear(client, project, service string, serviceMeta M, repository, commitHash string, commitTags []string, commitMeta M, level int, handler H) IDiary

Dear returns a diary.Diary interface instance for consumption

- client: The shorthand code used to identify which client the log belongs to - project: The shorthand code used to identify which client-project the log belongs to - service: The shorthand code used to identify which service the log belongs to - serviceMeta: Can contain any other additional data that you may require on logs for troubleshooting (may be empty) [WARNING: Don't ever log personal data without first encrypting or salt-hashing the data.]

- repository: The URI of the source-code repository (may be empty) - commitHash: The shorthand hash of the given source commit that the service was built off of (may be empty) - commitTags: The tags associated with the given source commit that the service was built off of (may be empty) - commitMeta: Can contain any other additional data that you may require on logs for troubleshooting (may be empty) [WARNING: Don't ever log personal data without first encrypting or salt-hashing the data.]

- level: The default level to log at [NOTE: Normally NOTICE for production services] - handler: A routine to handle log entries [NOTE: ]

type IPage

type IPage interface {
	Parent() IDiary
	Debug(key string, value interface{})
	Info(category string, meta M)
	Notice(category string, meta M)
	Warning(category, message string, meta M)
	Error(category, message string, meta M)
	Fatal(category, message string, code int, meta M)
	Audit(category string, meta M)
	ToJson() []byte
	Scope(category string, scope S) error
}

An definition of the public functions for a page instance

type Log

type Log struct {
	Service  Service   `json:"service"`
	Commit   Commit    `json:"commit"`
	Chain    Chain     `json:"chain"`
	Level    string    `json:"level"`
	Category string    `json:"category"`
	Line     string    `json:"line"`
	Stack    string    `json:"stack"`
	Message  string    `json:"message"`
	Meta     M         `json:"meta"`
	Time     time.Time `json:"time"`
}

A public struct to encapsulate the log entry details

type M

type M map[string]interface{}

A package shorthand for a map[string]interface

type S

type S func(p IPage)

A package shorthand for a page scope function

type Service

type Service struct {
	Client          string   `json:"client"`
	Project         string   `json:"project"`
	Service         string   `json:"service"`
	Host            string   `json:"host"`
	HostIps         []string `json:"hostIps"`
	ProcessId       int      `json:"pid"`
	ParentProcessId int      `json:"ppid"`
	Meta            M        `json:"meta"`
}

A public struct to encapsulate the service details for a log entry

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL