Skip to content

Commit

Permalink
Allow JSON formatter to have json compliant extra vars (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
liranbg authored Jun 24, 2021
1 parent d6e2f32 commit 260b369
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 44 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- uses: actions/setup-go@v2
with:
go-version: "1.14"

- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run lint
run: |
make lint
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- uses: actions/setup-go@v2
with:
go-version: "1.14"

- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run unit tests
run: |
make test-unit
64 changes: 64 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright 2021 The Nuclio Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


.PHONY: fmt
fmt: ## Code formatting
gofmt -s -w .

.PHONY: lint
lint: modules ## Code linting
@echo Installing linters...
@test -e $(GOPATH)/bin/impi || \
(mkdir -p $(GOPATH)/bin && \
curl -s https://api.github.com/repos/pavius/impi/releases/latest \
| grep -i "browser_download_url.*impi.*$(OS_NAME)" \
| cut -d : -f 2,3 \
| tr -d \" \
| wget -O $(GOPATH)/bin/impi -qi - \
&& chmod +x $(GOPATH)/bin/impi)

@test -e $(GOPATH)/bin/golangci-lint || \
(curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.36.0)

@echo Verifying imports...
$(GOPATH)/bin/impi \
--local github.com/nuclio/zap/ \
--scheme stdLocalThirdParty \
./...

@echo Linting...
$(GOPATH)/bin/golangci-lint run -v
@echo Done.


.PHONY: modules
modules: ensure-gopath ## Download go module packages
@echo Getting go modules
@go mod download

.PHONY: ensure-gopath
ensure-gopath: ## Ensure GOPATH env is set
ifndef GOPATH
$(error GOPATH must be set)
endif


.PHONY: test-unit
test-unit: ## Run unit tests
go test -v ./... -short

.PHONY: help
help: ## Display available commands
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# zap

A Nuclio.Logger wrapper for [zap](https://github.com/uber-go/zap)
10 changes: 4 additions & 6 deletions buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

var ErrBufferPoolAllocationTimeout = errors.New("Timed out waiting for buffer logger")

// a logger who outputs the records to a buffer
// BufferLogger is a logger who outputs the records to a buffer
type BufferLogger struct {
encoding string
Logger *NuclioZap
Expand Down Expand Up @@ -79,23 +79,21 @@ func (bl *BufferLogger) GetLogEntries() ([]map[string]interface{}, error) {
return nil, errors.Wrap(err, "Failed to get JSON string")
}

unmarshalledJSONBody := []map[string]interface{}{}
var unmarshalledJSONBody []map[string]interface{}

err = json.Unmarshal([]byte(jsonBody), &unmarshalledJSONBody)
if err != nil {
if err := json.Unmarshal([]byte(jsonBody), &unmarshalledJSONBody); err != nil {
return nil, errors.Wrap(err, "Failed to unmarshal JSON body")
}

return unmarshalledJSONBody, nil
}

// a pool for buffer loggers
// BufferLoggerPool is a pool for buffer loggers
type BufferLoggerPool struct {
bufferLoggerChan chan *BufferLogger
defaultAllocateTimeout time.Duration
}

// a pool of buffer loggers
func NewBufferLoggerPool(numBufferLoggers int,
name string,
encoding string,
Expand Down
91 changes: 65 additions & 26 deletions buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,56 @@ type BufferLoggerTestSuite struct {
suite.Suite
}

func (suite *BufferLoggerTestSuite) TestJSONencoding() {
func (suite *BufferLoggerTestSuite) TestJSONEncoding() {
bufferLogger, err := NewBufferLogger("test", "json", InfoLevel)
suite.Require().NoError(err, "Failed creating buffer logger")

suite.verifyLoggedJSONEntries(bufferLogger)
}

func (suite *BufferLoggerTestSuite) TestJSONEncodingAndStructuredVars() {
bufferLogger, err := NewBufferLogger("test", "json", InfoLevel)
suite.Require().NoError(err, "Failed creating buffer logger")

bufferLogger.Logger.customEncoderConfig = NewEncoderConfig()
bufferLogger.Logger.customEncoderConfig.JSON.VarGroupName = "testVars"
bufferLogger.Logger.customEncoderConfig.JSON.VarGroupMode = VarGroupModeStructured
bufferLogger.Logger.prepareVarsCallback = bufferLogger.Logger.prepareVarsStructured
suite.verifyLoggedJSONEntries(bufferLogger)
}

func (suite *BufferLoggerTestSuite) TestEmptyJSONEncoding() {
bufferLogger, err := NewBufferLogger("test", "json", InfoLevel)
suite.Require().NoError(err, "Failed creating buffer logger")

// get log entries
logEntries, err := bufferLogger.GetLogEntries()
suite.Require().NoError(err, "Failed to get log entries")

// verify there's nothing there
suite.Require().Len(logEntries, 0)
}

func (suite *BufferLoggerTestSuite) TestGetJSONWithNonJSONEncoding() {
bufferLogger, err := NewBufferLogger("test", "console", InfoLevel)
suite.Require().NoError(err, "Failed creating buffer logger")

// get log entries
logEntries, err := bufferLogger.GetLogEntries()
suite.Require().Error(err)
suite.Require().Nil(logEntries)
}

func (suite *BufferLoggerTestSuite) verifyLoggedJSONEntries(bufferLogger *BufferLogger) {

varsStructured := false
varsGroupName := ""
if bufferLogger.Logger.customEncoderConfig != nil &&
bufferLogger.Logger.customEncoderConfig.JSON.VarGroupMode == VarGroupModeStructured {
varsStructured = true
varsGroupName = bufferLogger.Logger.customEncoderConfig.JSON.VarGroupName
}

// write a few entries
bufferLogger.Logger.Debug("Unstructured %s", "debug")
bufferLogger.Logger.DebugWith("Structured debug", "mode", "debug")
Expand All @@ -50,41 +96,34 @@ func (suite *BufferLoggerTestSuite) TestJSONencoding() {
suite.Require().Equal("info", logEntries[0]["level"])
suite.Require().Equal("Structured info", logEntries[1]["message"])
suite.Require().Equal("info", logEntries[1]["level"])
suite.Require().Equal("info", logEntries[1]["mode"])

if varsStructured {
suite.Require().Equal(map[string]interface{}{"mode": "info"}, logEntries[1][varsGroupName])
} else {
suite.Require().Equal("info", logEntries[1]["mode"])

}

suite.Require().Equal("Unstructured warn", logEntries[2]["message"])
suite.Require().Equal("warn", logEntries[2]["level"])
suite.Require().Equal("Structured warn", logEntries[3]["message"])
suite.Require().Equal("warn", logEntries[3]["level"])
suite.Require().Equal("warn", logEntries[3]["mode"])

if varsStructured {
suite.Require().Equal(map[string]interface{}{"mode": "warn"}, logEntries[3][varsGroupName])
} else {
suite.Require().Equal("warn", logEntries[3]["mode"])
}

suite.Require().Equal("Unstructured error", logEntries[4]["message"])
suite.Require().Equal("error", logEntries[4]["level"])
suite.Require().Equal("Structured error", logEntries[5]["message"])
suite.Require().Equal("error", logEntries[5]["level"])
suite.Require().Equal("error", logEntries[5]["mode"])
}

func (suite *BufferLoggerTestSuite) TestEmptyJSONEncoding() {
bufferLogger, err := NewBufferLogger("test", "json", InfoLevel)
suite.Require().NoError(err, "Failed creating buffer logger")

// get log entries
logEntries, err := bufferLogger.GetLogEntries()
suite.Require().NoError(err, "Failed to get log entries")

// verify there's nothing there
suite.Require().Len(logEntries, 0)
}

func (suite *BufferLoggerTestSuite) TestGetJSONWithNonJSONEncoding() {
bufferLogger, err := NewBufferLogger("test", "console", InfoLevel)
suite.Require().NoError(err, "Failed creating buffer logger")

// get log entries
logEntries, err := bufferLogger.GetLogEntries()
suite.Require().Error(err)
suite.Require().Nil(logEntries)
if varsStructured {
suite.Require().Equal(map[string]interface{}{"mode": "error"}, logEntries[5][varsGroupName])
} else {
suite.Require().Equal("error", logEntries[5]["mode"])
}
}

type BufferLoggerPoolTestSuite struct {
Expand Down
Loading

0 comments on commit 260b369

Please sign in to comment.