2 * Copyright (c) 2019 AT&T Intellectual Property.
3 * Copyright (c) 2018-2019 Nokia.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 * platform project (RICP).
21 // Package golog implements a simple structured logging with MDC (Mapped Diagnostics Context) support.
30 "k8s.io/utils/inotify"
40 // Level is a type define for the logging level.
44 // ERR is an error level log entry.
46 // WARN is a warning level log entry.
48 // INFO is an info level log entry.
50 // DEBUG is a debug level log entry.
54 // MdcLogger is the logger instance, created with InitLogger() function.
55 type MdcLogger struct {
64 type logEntry struct {
66 Crit string `json:"crit"`
68 Mdc map[string]string `json:"mdc"`
69 Msg string `json:"msg"`
72 func levelString(level Level) string {
87 func getTime() int64 {
88 ns := time.Time.UnixNano(time.Now())
89 return ns / int64(time.Millisecond)
92 func (l *MdcLogger) formatLog(level Level, msg string) ([]byte, error) {
93 log := logEntry{getTime(), levelString(level), l.proc, l.mdc, msg}
94 buf := bytes.NewBuffer(nil)
95 encoder := json.NewEncoder(buf)
96 encoder.SetEscapeHTML(false)
97 err := encoder.Encode(log)
98 return buf.Bytes(), err
101 func initLogger(proc string, writer io.Writer) (*MdcLogger, error) {
102 return &MdcLogger{proc: proc, writer: writer, mdc: make(map[string]string), level: DEBUG, init_done: 0}, nil
105 // InitLogger is the init routine which returns a new logger instance.
106 // The program identity is given as a parameter. The identity
107 // is added to every log writing.
108 // The function returns a new instance or an error.
109 func InitLogger(proc string) (*MdcLogger, error) {
110 return initLogger(proc, os.Stdout)
113 // Log is the basic logging function to write a log message with
115 func (l *MdcLogger) Log(level Level, formatMsg string, a ...interface{}) {
117 defer l.mutex.Unlock()
121 log, err := l.formatLog(level, fmt.Sprintf(formatMsg, a...))
127 // Error is the "error" level logging function.
128 func (l *MdcLogger) Error(formatMsg string, a ...interface{}) {
129 l.Log(ERR, formatMsg, a...)
132 // Warning is the "warning" level logging function.
133 func (l *MdcLogger) Warning(formatMsg string, a ...interface{}) {
134 l.Log(WARN, formatMsg, a...)
137 // Info is the "info" level logging function.
138 func (l *MdcLogger) Info(formatMsg string, a ...interface{}) {
139 l.Log(INFO, formatMsg, a...)
142 // Debug is the "debug" level logging function.
143 func (l *MdcLogger) Debug(formatMsg string, a ...interface{}) {
144 l.Log(DEBUG, formatMsg, a...)
147 // LevelSet sets the current logging level.
148 // Log writings with less significant level are discarded.
149 func (l *MdcLogger) LevelSet(level Level) {
153 // LevelGet returns the current logging level.
154 func (l *MdcLogger) LevelGet() Level {
158 // MdcAdd adds a new MDC key value pair to the logger.
159 func (l *MdcLogger) MdcAdd(key string, value string) {
161 defer l.mutex.Unlock()
165 // MdcRemove removes an MDC key from the logger.
166 func (l *MdcLogger) MdcRemove(key string) {
168 defer l.mutex.Unlock()
172 // MdcGet gets the value of an MDC from the logger.
173 // The function returns the value string and a boolean
174 // which tells if the key was found or not.
175 func (l *MdcLogger) MdcGet(key string) (string, bool) {
177 defer l.mutex.Unlock()
178 val, ok := l.mdc[key]
182 // MdcClean removes all MDC keys from the logger.
183 func (l *MdcLogger) MdcClean() {
185 defer l.mutex.Unlock()
186 l.mdc = make(map[string]string)
189 func (l *MdcLogger) MdcUpdate(key string, value string) {
190 _, ok := l.MdcGet(key)
197 func (l *MdcLogger) ParseFileContent(fileName string) {
198 data, err := ioutil.ReadFile(fileName)
200 fmt.Println("File reading error", err)
203 for _, lineData := range strings.Split(string(data), "\n") {
204 if strings.Contains(lineData, "log-level:") {
206 strList := strings.Split(lineData, ":")
207 if strings.Contains(strings.ToUpper(strList[1]), "DEBUG") {
209 } else if strings.Contains(strings.ToUpper(strList[1]), "INFO") {
211 } else if strings.Contains(strings.ToUpper(strList[1]), "ERR") {
213 } else if strings.Contains(strings.ToUpper(strList[1]), "WARN") {
221 func (l *MdcLogger) watch_changes(watcher *inotify.Watcher, fileName string) {
224 case ev := <-watcher.Event:
225 if strings.Contains(ev.Name, filepath.Dir(fileName)) {
226 l.ParseFileContent(fileName)
228 case err := <-watcher.Error:
229 fmt.Println("error:", err)
234 func (l *MdcLogger) readEnvVar(envKey string) string {
235 envValue, provided := os.LookupEnv(envKey)
242 func (l *MdcLogger) Mdclog_format_initialize(logFileMonitor int) int {
244 logFields := []string{"SYSTEM_NAME", "HOST_NAME", "SERVICE_NAME", "CONTAINER_NAME", "POD_NAME"}
245 for _, envKey := range logFields {
246 envValue := l.readEnvVar(envKey)
247 l.MdcUpdate(envKey, envValue)
249 l.MdcUpdate("PID", strconv.Itoa(os.Getpid()))
250 if logFileMonitor > 0 {
251 watchPath := l.readEnvVar("CONFIG_MAP_NAME")
252 _, err := os.Stat(watchPath)
253 if !os.IsNotExist(err) {
254 if l.init_done == 0 {
258 watcher, err := inotify.NewWatcher()
262 err = watcher.AddWatch(filepath.Dir(watchPath), syscall.IN_CLOSE_WRITE|syscall.IN_CREATE|syscall.IN_CLOSE)
266 l.ParseFileContent(watchPath)
267 go l.watch_changes(watcher, watchPath)