Skip to content

Commit

Permalink
Merge branch 'release/v1.3.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
gildas committed Apr 8, 2020
2 parents f5c8c65 + 95f73d2 commit 04956ee
Show file tree
Hide file tree
Showing 26 changed files with 346 additions and 175 deletions.
84 changes: 82 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# go-logger

[![GoDoc](https://godoc.org/github.com/gildas/go-logger?status.svg)](https://godoc.org/github.com/gildas/go-logger)
go-logger is a logging library based on [node-bunyan](trentm/node-bunyan).
![GoVersion](https://img.shields.io/github/go-mod/go-version/gildas/go-logger)
[![GoDoc](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/gildas/go-logger)
[![License](https://img.shields.io/github/license/gildas/go-logger)](https://github.com/gildas/go-logger/blob/master/LICENSE)
[![Report](https://goreportcard.com/badge/github.com/gildas/go-logger)](https://goreportcard.com/report/github.com/gildas/go-logger)

go-logger is a logging library based on [node-bunyan](https://github.com/trentm/node-bunyan).

The output is compatible with the `bunyan` log reader application from that `node` package.

Expand Down Expand Up @@ -306,6 +310,80 @@ func main() {
}
```

## Obfuscation

There might be some situation where some parts of the logged messages have to be obfuscated. Typical usage could be:
- Hiding passwords
- Hiding personal information to comply to regulations such as HIPAA, PCI-DSS

To achieve this, the logger can obfuscate automatically or manually. Manually, the easiest of all, is when the obfuscation is called from the source code directly:

```go
func Authenticate(user, password string) bool {
Log.Debugf("Authenticating User: %s with Password: %s", user, logger.Obfuscate(password))
if user == "admin" && password == "SuperS3cr3t" {
Log.Infof("User %s is authenticated via super complex authentication", user)
return true
}
Log.Warnf("Invalid Credentials for user %s", user)
return false
}
```

The advantage of this method is the total control what is to be obfuscated. Its disadvantage is obvious, we need to add knowledge in the code...

The automated way is configured by adding regular expressions to the `Obfuscator`:

```go
func main() {
Log := logger.Create("MYAPP", logger.ObfuscateRule{`4[0-9]{12}(?:[0-9]{3})?`}) // Obfuscate VISA card number
Log.ObfuscateRule('3[47][0-9]{13}') // Obfuscate also AMEX card numbers
// . . .
Log.Debugf("Credit card entered: %s", visacard)
}
```

As seen in this code, obfuscation rules can be added at the logger's creation time or later in the code.

It is also possible to instruct the Obfuscator to process some properties of struct types:

```go
type Stuff struct {
ID string
Secret string `logger:"obfuscate"`
}

func main() {
Log := logger.Create()
stuff := Stuff{}
// . . .
Log.Infof("Found stuff: %v", stuff)
}
```

To obfuscate, a random SHA-256/AES?!? key is created at the beginning on the application and is used to hash the target data.

If you need reversible obfuscation, create an SSL key pair, and provide the logger with the public key via the environment variable `LOG_OBFUSCATION_KEY`.

To decode the obfuscated data, you will need to manually use the private key with tools like `openssl` or `gpg`.

Food for thoughts:

- symetric key/password
```console
encrypted=$(echo "Hello" | openssl enc -aes-256-cbc -pbkdf2 -a -iter 20000 -k yummy)
echo $encrypted| base64 -d | openssl enc -d -aes-256-cbc -pbkdf2 -iter 20000 -k yummy
```

- public/private key
```console
openssl genrsa -out ~/.ssh/logkey
openssl rsa -in ~/.ssh/logkey -out ~/.ssl/logkey.pub -pubout # Default format is PEM
encrypted=$(echo "Hello" | openssl rsautl -encrypt -inkey tmp/mykey.pub -pubin | base64)

echo $encrypted | base64 -d | openssl rsautl -decrypt -inkey tmp/mykey
```

## Environment Variables

The `Logger` can be configured completely by environment variables if needed. These are:
Expand All @@ -317,6 +395,8 @@ The `Logger` can be configured completely by environment variables if needed. Th
The default `Converter` to use
- `LOG_FLUSHFREQUENCY`, default: 5 minutes
The default Flush Frequency for the streams that will be buffered
- `LOG_OBFUSCATION_KEY`, default: none
The SSL public key to use when obfuscating if you want a reversible obfuscation
- `GOOGLE_APPLICATION_CREDENTIALS`
The path to the credential file for the `StackDriverStream`
- `GOOGLE_PROJECT_ID`
Expand Down
5 changes: 2 additions & 3 deletions common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func (v *BogusValue) MarshalJSON() ([]byte, error) {
return nil, fmt.Errorf("Failed to Marshal BogusValue")
}


// Load loads an object from a file and marshals it
func Load(filename string, object interface{}) (err error) {
var payload []byte
Expand Down Expand Up @@ -75,7 +74,7 @@ func CreateLogger(t *testing.T, filename string, wantLocal bool) (*logger.Logger
folder, teardown = CreateTempDir(t)
}
path := filepath.Join(folder, filename)
log := logger.CreateWithDestination("test", "file://" + path)
log := logger.CreateWithDestination("test", "file://"+path)
//if _, err := os.Stat(path); err != nil {
// t.Fatalf("Log file was not created at: %s. Error: %s\n", path, err)
//}
Expand Down Expand Up @@ -138,4 +137,4 @@ func CaptureStdout(f func()) string {
output := bytes.Buffer{}
_, _ = io.Copy(&output, reader)
return output.String()
}
}
3 changes: 2 additions & 1 deletion converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package logger

import (
"strings"

"github.com/gildas/go-core"
)

Expand All @@ -20,4 +21,4 @@ func GetConverterFromEnvironment() Converter {
default:
return &BunyanConverter{}
}
}
}
2 changes: 1 addition & 1 deletion converter_bunyan.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ func (converter *BunyanConverter) Convert(record Record) Record {
}
}
return record
}
}
4 changes: 2 additions & 2 deletions converter_stackdriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type StackDriverConverter struct {
func (converter *StackDriverConverter) Convert(record Record) Record {
// StackDriver special fields: https://cloud.google.com/logging/docs/agent/configuration#special-fields
record["severity"] = severity(record["level"])
record["message"] = record["msg"]
record["message"] = record["msg"]
if value, ok := record["time"]; ok {
if rtime, ok := value.(time.Time); ok {
record["time"] = rtime.Format(time.RFC3339)
Expand Down Expand Up @@ -51,4 +51,4 @@ func severity(value interface{}) logging.Severity {
default:
return logging.Info
}
}
}
42 changes: 22 additions & 20 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ Here is a simple example how Record fields can be used with a type:
The call to Record(key, value) creates a new Logger object.
So, they are like Russian dolls when it comes down to actually
writing the log message to the output stream.
writing the log message to the output stream.
In other words, Record objects are collected from their parent's `Logger`
back to the original `Logger.
back to the original Logger.
For example:
For example:
var Log = logger.Create("test")
var child = Log.Record("key1", "value1").Record("key2", "value2")
Expand Down Expand Up @@ -123,10 +124,10 @@ You can also create a Logger by passing it a Stream object (these are equivalent
A few notes:
- logger.CreateWithStream can also be used to create with one or more streams.
- logger.CreateWithStream can also be used to create with one or more streams.
(Backward compatibility)
- logger.CreateWithDestination can also be used to create with one or more destinations.
- logger.CreateWithDestination can also be used to create with one or more destinations.
(Backward compatibility)
- the StackDriverStream needs a LogID parameter or the value of the environment variable GOOGLE_PROJECT_ID.
Expand Down Expand Up @@ -166,20 +167,20 @@ since the standard output of your application will be captured automatically by
To be able to use the StackDriver Stream from outside Google Cloud, you have some configuration to do first.
On your workstation, you need to get the key filename:
1. Authenticate with Google Cloud
On your workstation, you need to get the key filename:
1. Authenticate with Google Cloud
gcloud auth login
2. Create a Service Account (`logger-account` is just an example of a service account name)
2. Create a Service Account (`logger-account` is just an example of a service account name)
gcloud iam service-acccount create logger-account
3. Associate the Service Account to the Project you want to use
3. Associate the Service Account to the Project you want to use
gcloud projects add-iam-policy-binding my-logging-project \
--member "serviceAccount:[email protected]" \
--role "roles/logging.logWriter"
4. Retrieve the key filename
gcloud iam service-accounts keys create /path/to/key.json \
--iam-account [email protected]
You can either set the GOOGLE_APPLICATION_CREDENTIAL and GOOGLE_PROJECT_ID environment variables
You can either set the GOOGLE_APPLICATION_CREDENTIAL and GOOGLE_PROJECT_ID environment variables
with the path of the obtained key and Google Project ID or provide them to the StackDriver stream:
var Log = logger.Create("myapp", &logger.StackDriverStream{})
Expand Down Expand Up @@ -226,7 +227,7 @@ Here is a list of all the converters:
Writing your own Converter
You can also write your own Converter by implementing the logger.Converter interface:
You can also write your own Converter by implementing the logger.Converter interface:
type MyConverter struct {
// ...
Expand Down Expand Up @@ -275,27 +276,28 @@ Here is an example:
Environment Variables
The Logger can be configured completely by environment variables if needed. These are:
The Logger can be configured completely by environment variables if needed. These are:
LOG_DESTINATION, default: StdoutStream
LOG_DESTINATION, default: StdoutStream
The Stream to write logs to. It can be a comma-separated list (for a MultiStream)
LOG_LEVEL, default: INFO
LOG_LEVEL, default: INFO
The level to filter by default. If the environment DEBUG is set the default level is DEBUG
LOG_CONVERTER, default: bunyan
LOG_CONVERTER, default: bunyan
The default Converter to use
LOG_FLUSHFREQUENCY, default: 5 minutes
LOG_FLUSHFREQUENCY, default: 5 minutes
The default Flush Frequency for the streams that will be buffered
GOOGLE_APPLICATION_CREDENTIALS
GOOGLE_APPLICATION_CREDENTIALS
The path to the credential file for the StackDriverStream
GOOGLE_PROJECT_ID
GOOGLE_PROJECT_ID
The Google Cloud Project ID for the StackDriverStream
DEBUG, default: none
DEBUG, default: none
If set to "1", this will set the default level to filter to DEBUG
*/
package logger

package logger
17 changes: 7 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@ module github.com/gildas/go-logger
go 1.13

require (
cloud.google.com/go v0.52.0 // indirect
cloud.google.com/go v0.56.0 // indirect
cloud.google.com/go/logging v1.0.0
github.com/gildas/go-core v0.4.1
github.com/gildas/go-core v0.4.4
github.com/gildas/go-errors v0.1.0
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.7.3
github.com/gorilla/mux v1.7.4
github.com/stretchr/testify v1.4.0
go.opencensus.io v0.22.3 // indirect
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 // indirect
google.golang.org/api v0.16.0
google.golang.org/genproto v0.0.0-20200205142000-a86caf926a67 // indirect
google.golang.org/grpc v1.27.1 // indirect
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b // indirect
google.golang.org/api v0.21.0
google.golang.org/genproto v0.0.0-20200407120235-9eb9bb161a06 // indirect
google.golang.org/grpc v1.28.1 // indirect
)
Loading

0 comments on commit 04956ee

Please sign in to comment.