First commit
This commit is contained in:
187
setup/e2mgr/E2Manager/logger/logger.go
Normal file
187
setup/e2mgr/E2Manager/logger/logger.go
Normal file
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// Copyright 2019 AT&T Intellectual Property
|
||||
// Copyright 2019 Nokia
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
|
||||
// platform project (RICP).
|
||||
|
||||
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
// Copied from zap logger
|
||||
//
|
||||
// A Level is a logging priority. Higher levels are more important.
|
||||
type LogLevel int8
|
||||
|
||||
const (
|
||||
// DebugLevel logs are typically voluminous, and are usually disabled in
|
||||
// production.
|
||||
DebugLevel LogLevel = iota - 1
|
||||
// InfoLevel is the default logging priority.
|
||||
InfoLevel
|
||||
// WarnLevel logs are more important than Info, but don't need individual
|
||||
// human review.
|
||||
WarnLevel
|
||||
// ErrorLevel logs are high-priority. If an application is running smoothly,
|
||||
// it shouldn't generate any error-level logs.
|
||||
ErrorLevel
|
||||
// DPanicLevel logs are particularly important errors. In development the
|
||||
// logger panics after writing the message.
|
||||
DPanicLevel
|
||||
// PanicLevel logs a message, then panics.
|
||||
PanicLevel
|
||||
// FatalLevel logs a message, then calls os.Exit(1).
|
||||
FatalLevel
|
||||
|
||||
_minLevel = DebugLevel
|
||||
_maxLevel = FatalLevel
|
||||
)
|
||||
|
||||
var logLevelTokenToLevel = map[string] LogLevel {
|
||||
"debug" : DebugLevel,
|
||||
"info": InfoLevel,
|
||||
"warn": WarnLevel,
|
||||
"error": ErrorLevel,
|
||||
"dpanic": DPanicLevel,
|
||||
"panic": PanicLevel,
|
||||
"fatal": FatalLevel,
|
||||
}
|
||||
|
||||
func LogLevelTokenToLevel(level string) (LogLevel, bool) {
|
||||
if level, ok := logLevelTokenToLevel[strings.TrimSpace(strings.ToLower(level))];ok {
|
||||
return level, true
|
||||
}
|
||||
return _maxLevel+1, false
|
||||
}
|
||||
|
||||
func InitLogger(requested LogLevel) (*Logger, error) {
|
||||
var logger *zap.Logger
|
||||
var err error
|
||||
switch requested {
|
||||
case DebugLevel:
|
||||
logger, err = initLoggerByLevel(zapcore.DebugLevel)
|
||||
case InfoLevel:
|
||||
logger, err = initLoggerByLevel(zapcore.InfoLevel)
|
||||
case WarnLevel:
|
||||
logger, err = initLoggerByLevel(zapcore.WarnLevel)
|
||||
case ErrorLevel:
|
||||
logger, err = initLoggerByLevel(zapcore.ErrorLevel)
|
||||
case DPanicLevel:
|
||||
logger, err = initLoggerByLevel(zapcore.DPanicLevel)
|
||||
case PanicLevel:
|
||||
logger, err = initLoggerByLevel(zapcore.PanicLevel)
|
||||
case FatalLevel:
|
||||
logger, err = initLoggerByLevel(zapcore.FatalLevel)
|
||||
default:
|
||||
err = fmt.Errorf("Invalid logging Level :%d",requested)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Logger{Logger:logger}, nil
|
||||
|
||||
}
|
||||
func(l *Logger)Sync() error {
|
||||
l.Debugf("#logger.Sync - Going to flush buffered log")
|
||||
return l.Logger.Sync()
|
||||
}
|
||||
|
||||
func (l *Logger)Infof(formatMsg string, a ...interface{}) {
|
||||
if l.InfoEnabled() {
|
||||
msg := fmt.Sprintf(formatMsg, a...)
|
||||
l.Logger.Info(msg, zap.Any("mdc", l.getTimeStampMdc()))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger)Debugf(formatMsg string, a ...interface{}) {
|
||||
if l.DebugEnabled(){
|
||||
msg := fmt.Sprintf(formatMsg, a...)
|
||||
l.Logger.Debug(msg, zap.Any("mdc", l.getTimeStampMdc()))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger)Errorf(formatMsg string, a ...interface{}) {
|
||||
msg := fmt.Sprintf(formatMsg, a...)
|
||||
l.Logger.Error(msg, zap.Any("mdc", l.getTimeStampMdc()))
|
||||
}
|
||||
|
||||
func (l *Logger)Warnf(formatMsg string, a ...interface{}) {
|
||||
msg := fmt.Sprintf(formatMsg, a...)
|
||||
l.Logger.Warn(msg, zap.Any("mdc", l.getTimeStampMdc()))
|
||||
}
|
||||
|
||||
func (l *Logger) getTimeStampMdc() map[string]string {
|
||||
timeStr := time.Now().Format("2006-01-02 15:04:05.000")
|
||||
mdc := map[string]string{"time": timeStr}
|
||||
return mdc
|
||||
}
|
||||
|
||||
func (l *Logger)InfoEnabled()bool{
|
||||
return l.Logger.Core().Enabled(zap.InfoLevel)
|
||||
}
|
||||
|
||||
func (l *Logger)DebugEnabled()bool{
|
||||
return l.Logger.Core().Enabled(zap.DebugLevel)
|
||||
}
|
||||
|
||||
func (l *Logger)DPanicf(formatMsg string, a ...interface{}) {
|
||||
msg := fmt.Sprintf(formatMsg, a...)
|
||||
l.Logger.DPanic(msg, zap.Any("mdc", l.getTimeStampMdc()))
|
||||
}
|
||||
|
||||
func initLoggerByLevel(l zapcore.Level) (*zap.Logger, error) {
|
||||
cfg := zap.Config{
|
||||
Encoding: "json",
|
||||
Level: zap.NewAtomicLevelAt(l),
|
||||
OutputPaths: []string{"stdout"},
|
||||
ErrorOutputPaths: []string{"stderr"},
|
||||
EncoderConfig: zapcore.EncoderConfig{
|
||||
MessageKey: "msg",
|
||||
|
||||
LevelKey: "crit",
|
||||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||||
|
||||
TimeKey: "ts",
|
||||
EncodeTime: epochMillisIntegerTimeEncoder,
|
||||
|
||||
CallerKey: "id",
|
||||
EncodeCaller: e2ManagerCallerEncoder,
|
||||
},
|
||||
}
|
||||
return cfg.Build()
|
||||
}
|
||||
|
||||
func e2ManagerCallerEncoder(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
|
||||
enc.AppendString("E2Manager")
|
||||
}
|
||||
|
||||
func epochMillisIntegerTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||
nanos := t.UnixNano()
|
||||
millis := int64(nanos) / int64(time.Millisecond)
|
||||
enc.AppendInt64(millis)
|
||||
}
|
||||
|
293
setup/e2mgr/E2Manager/logger/logger_test.go
Normal file
293
setup/e2mgr/E2Manager/logger/logger_test.go
Normal file
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// Copyright 2019 AT&T Intellectual Property
|
||||
// Copyright 2019 Nokia
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
|
||||
// platform project (RICP).
|
||||
|
||||
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInitDebugLoggerSuccess(t *testing.T) {
|
||||
log, err := InitLogger(DebugLevel)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, log)
|
||||
assert.True(t, log.Logger.Core().Enabled(zap.DebugLevel))
|
||||
}
|
||||
|
||||
func TestInitInfoLoggerSuccess(t *testing.T) {
|
||||
log, err := InitLogger(InfoLevel)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, log)
|
||||
assert.True(t, log.Logger.Core().Enabled(zap.InfoLevel))
|
||||
}
|
||||
|
||||
func TestInitWarnLoggerSuccess(t *testing.T) {
|
||||
log, err := InitLogger(WarnLevel)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, log)
|
||||
assert.True(t, log.Logger.Core().Enabled(zap.WarnLevel))
|
||||
}
|
||||
|
||||
func TestInitErrorLoggerSuccess(t *testing.T) {
|
||||
log, err := InitLogger(ErrorLevel)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, log)
|
||||
assert.True(t, log.Logger.Core().Enabled(zap.ErrorLevel))
|
||||
}
|
||||
|
||||
func TestInitDPanicLoggerSuccess(t *testing.T) {
|
||||
log, err := InitLogger(DPanicLevel)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, log)
|
||||
assert.True(t, log.Logger.Core().Enabled(zap.DPanicLevel))
|
||||
}
|
||||
|
||||
func TestInitPanicLoggerSuccess(t *testing.T) {
|
||||
log, err := InitLogger(PanicLevel)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, log)
|
||||
assert.True(t, log.Logger.Core().Enabled(zap.PanicLevel))
|
||||
}
|
||||
|
||||
func TestInitInfoLoggerFailure(t *testing.T) {
|
||||
log, err := InitLogger(99)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, log)
|
||||
}
|
||||
|
||||
func TestSyncSuccess(t *testing.T){
|
||||
logFile, err := os.Create("./loggerTest.txt")
|
||||
if err != nil{
|
||||
t.Errorf("logger_test.TestSyncSuccess - failed to create file, error: %s", err)
|
||||
}
|
||||
old := os.Stdout
|
||||
os.Stdout = logFile
|
||||
log, err := InitLogger(DebugLevel)
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncSuccess - failed to initialize logger, error: %s", err)
|
||||
}
|
||||
err = log.Sync()
|
||||
assert.Nil(t, err)
|
||||
|
||||
os.Stdout = old
|
||||
logFile, err = os.Open("./loggerTest.txt")
|
||||
if err != nil{
|
||||
t.Errorf("logger_test.TestSyncSuccess - failed to open file, error: %s", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, logFile)
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncSuccess - failed to copy bytes, error: %s", err)
|
||||
}
|
||||
debugRecord,_ :=buf.ReadString('\n')
|
||||
errorRecord,_ :=buf.ReadString('\n')
|
||||
|
||||
assert.NotEmpty(t, debugRecord)
|
||||
assert.Empty(t, errorRecord)
|
||||
err = os.Remove("./loggerTest.txt")
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncSuccess - failed to remove file, error: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSyncFailure(t *testing.T){
|
||||
log, err := InitLogger(DebugLevel)
|
||||
err = log.Sync()
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestDebugEnabledFalse(t *testing.T){
|
||||
entryNum, log := countRecords(InfoLevel, t)
|
||||
assert.False(t, log.DebugEnabled())
|
||||
assert.Equal(t,3, entryNum)
|
||||
}
|
||||
|
||||
func TestDebugEnabledTrue(t *testing.T){
|
||||
entryNum, log := countRecords(DebugLevel, t)
|
||||
assert.True(t, log.DebugEnabled())
|
||||
assert.Equal(t,4, entryNum)
|
||||
}
|
||||
|
||||
func TestDPanicfDebugLevel(t *testing.T){
|
||||
assert.True(t,validateRecordExists(DebugLevel, zap.DPanicLevel, t))
|
||||
}
|
||||
|
||||
func TestDPanicfInfoLevel(t *testing.T){
|
||||
assert.True(t,validateRecordExists(InfoLevel, zap.DPanicLevel, t))
|
||||
}
|
||||
|
||||
func TestErrorfDebugLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(DebugLevel, zap.ErrorLevel, t))
|
||||
}
|
||||
|
||||
func TestErrorfInfoLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(InfoLevel, zap.ErrorLevel, t))
|
||||
}
|
||||
|
||||
func TestInfofDebugLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(DebugLevel, zap.InfoLevel, t))
|
||||
}
|
||||
|
||||
func TestInfofInfoLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(InfoLevel, zap.InfoLevel, t))
|
||||
}
|
||||
|
||||
func TestDebugfDebugLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(DebugLevel, zap.DebugLevel, t))
|
||||
}
|
||||
|
||||
func TestDebugfInfoLevel(t *testing.T) {
|
||||
assert.False(t,validateRecordExists(InfoLevel, zap.DebugLevel, t))
|
||||
}
|
||||
|
||||
func TestInfofFatalLevel(t *testing.T) {
|
||||
assert.False(t,validateRecordExists(FatalLevel, zap.InfoLevel, t))
|
||||
}
|
||||
|
||||
func TestDebugfFatalLevel(t *testing.T) {
|
||||
assert.False(t,validateRecordExists(FatalLevel, zap.DebugLevel, t))
|
||||
}
|
||||
|
||||
func TestWarnfWarnLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(WarnLevel, zap.WarnLevel, t))
|
||||
}
|
||||
|
||||
func TestWarnfDebugLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(DebugLevel, zap.WarnLevel, t))
|
||||
}
|
||||
|
||||
func TestWarnfInfoLevel(t *testing.T) {
|
||||
assert.True(t,validateRecordExists(InfoLevel, zap.WarnLevel, t))
|
||||
}
|
||||
|
||||
func TestWarnfFatalLevel(t *testing.T) {
|
||||
assert.False(t,validateRecordExists(FatalLevel, zap.WarnLevel, t))
|
||||
}
|
||||
|
||||
func TestLogLevelTokenToLevel(t *testing.T) {
|
||||
level, ok := LogLevelTokenToLevel("deBug")
|
||||
assert.True(t, ok)
|
||||
assert.True(t, level == DebugLevel)
|
||||
|
||||
level, ok = LogLevelTokenToLevel("infO")
|
||||
assert.True(t, ok)
|
||||
assert.True(t, level == InfoLevel)
|
||||
|
||||
level, ok = LogLevelTokenToLevel("Warn")
|
||||
assert.True(t, ok)
|
||||
assert.True(t, level == WarnLevel)
|
||||
|
||||
level, ok = LogLevelTokenToLevel("eRror")
|
||||
assert.True(t, ok)
|
||||
assert.True(t, level == ErrorLevel)
|
||||
|
||||
level, ok = LogLevelTokenToLevel("Dpanic ")
|
||||
assert.True(t, ok)
|
||||
assert.True(t, level == DPanicLevel)
|
||||
|
||||
level, ok = LogLevelTokenToLevel(" panic ")
|
||||
assert.True(t, ok)
|
||||
assert.True(t, level == PanicLevel)
|
||||
|
||||
level, ok = LogLevelTokenToLevel("fatal")
|
||||
assert.True(t, ok)
|
||||
assert.True(t, level == FatalLevel)
|
||||
|
||||
level, ok = LogLevelTokenToLevel("zzz")
|
||||
assert.False(t, ok)
|
||||
assert.True(t, level > FatalLevel)
|
||||
|
||||
}
|
||||
func countRecords(logLevel LogLevel, t *testing.T) (int, *Logger){
|
||||
old := os.Stdout
|
||||
r, w, _ :=os.Pipe()
|
||||
os.Stdout = w
|
||||
log, err := InitLogger(logLevel)
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncFailure - failed to initialize logger, error: %s", err)
|
||||
}
|
||||
log.Infof("%v, %v, %v", 1, "abc", 0.1)
|
||||
log.Debugf("%v, %v, %v", 1, "abc", 0.1)
|
||||
log.Errorf("%v, %v, %v", 1, "abc", 0.1)
|
||||
log.DPanicf("%v, %v, %v", 1, "abc", 0.1)
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncFailure - failed to close writer, error: %s", err)
|
||||
}
|
||||
os.Stdout = old
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, r)
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncFailure - failed to copy bytes, error: %s", err)
|
||||
}
|
||||
entryNum := 0
|
||||
s,_:= buf.ReadString('\n')
|
||||
for len(s) > 0{
|
||||
entryNum +=1
|
||||
s,_= buf.ReadString('\n')
|
||||
}
|
||||
return entryNum, log
|
||||
}
|
||||
|
||||
func validateRecordExists(logLevel LogLevel, recordLevel zapcore.Level, t *testing.T) bool {
|
||||
old := os.Stdout
|
||||
r, w, _ :=os.Pipe()
|
||||
os.Stdout = w
|
||||
log, err := InitLogger(logLevel)
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncFailure - failed to initialize logger, error: %s", err)
|
||||
}
|
||||
switch recordLevel{
|
||||
case zap.DebugLevel:
|
||||
log.Debugf("%v, %v, %v", 1, "abc", 0.1)
|
||||
case zap.InfoLevel:
|
||||
log.Infof("%v, %v, %v", 1, "abc", 0.1)
|
||||
case zap.WarnLevel:
|
||||
log.Warnf("%v, %v, %v", 1, "abc", 0.1)
|
||||
case zap.ErrorLevel:
|
||||
log.Errorf("%v, %v, %v", 1, "abc", 0.1)
|
||||
case zap.DPanicLevel:
|
||||
log.DPanicf("%v, %v, %v", 1, "abc", 0.1)
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncFailure - failed to close writer, error: %s", err)
|
||||
}
|
||||
os.Stdout = old
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, r)
|
||||
if err != nil {
|
||||
t.Errorf("logger_test.TestSyncFailure - failed to copy bytes, error: %s", err)
|
||||
}
|
||||
entryNum := 0
|
||||
s,_:= buf.ReadString('\n')
|
||||
for len(s) > 0{
|
||||
entryNum +=1
|
||||
s,_= buf.ReadString('\n')
|
||||
}
|
||||
return entryNum == 1
|
||||
}
|
Reference in New Issue
Block a user