blob: 914fc7b5e06b60ee937d5b8bd2af860988503b8e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package model
import (
"os"
"path/filepath"
"time"
)
import (
"github.com/apache/dubbo-go-pixiu/pkg/common/constant"
"github.com/apache/dubbo-go-pixiu/pkg/logger"
)
// access log config, enable default value true, outputpath default value console
// access log will out put into console
type AccessLogConfig struct {
Enable bool `yaml:"enable" json:"enable" mapstructure:"enable" default:"true"`
OutPutPath string `yaml:"outPutPath" json:"outPutPath" mapstructure:"outPutPath" default:"console"`
}
// access log chan
type AccessLogWriter struct {
AccessLogDataChan chan AccessLogData
}
// access log data
type AccessLogData struct {
AccessLogMsg string
AccessLogConfig AccessLogConfig
}
// writer msg into chan
func (alw *AccessLogWriter) Writer(accessLogData AccessLogData) {
select {
case alw.AccessLogDataChan <- accessLogData:
return
default:
logger.Warn("the channel is full and the access logIntoChannel data will be dropped")
return
}
}
// write log into out put path
func (alw *AccessLogWriter) Write() {
go func() {
for accessLogData := range alw.AccessLogDataChan {
alw.writeLogToFile(accessLogData)
}
}()
}
// write log to file or console
func (alw *AccessLogWriter) writeLogToFile(ald AccessLogData) {
alc := ald.AccessLogConfig
alm := ald.AccessLogMsg
if len(alc.OutPutPath) == 0 || alc.OutPutPath == constant.Console {
logger.Info(alm)
return
}
_ = WriteToFile(alm, alc.OutPutPath)
}
// write message to access log file
func WriteToFile(accessLogMsg string, filePath string) error {
pd := filepath.Dir(filePath)
if _, err := os.Stat(pd); err != nil {
if os.IsExist(err) {
logger.Warnf("can not open log dir: %s, %v", filePath, err)
}
err = os.MkdirAll(pd, os.ModePerm)
if err != nil {
logger.Warnf("can not create log dir: %s, %v", filePath, err)
return err
}
}
logFile, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, constant.LogFileMode)
if err != nil {
logger.Warnf("can not open the access log file: %s, %v", filePath, err)
return err
}
now := time.Now().Format(constant.FileDateFormat)
fileInfo, err := logFile.Stat()
if err != nil {
logger.Warnf("can not get the info of access log file: %s, %v", filePath, err)
return err
}
last := fileInfo.ModTime().Format(constant.FileDateFormat)
// this is confused.
// for example, if the last = '2020-03-04'
// and today is '2020-03-05'
// we will create one new file to log access data
// By this way, we can split the access log based on days.
if now != last {
err = os.Rename(fileInfo.Name(), fileInfo.Name()+"."+now)
if err != nil {
logger.Warnf("can not rename access log file: %s, %v", fileInfo.Name(), err)
return err
}
logFile, err = os.OpenFile(fileInfo.Name(), os.O_CREATE|os.O_APPEND|os.O_RDWR, constant.LogFileMode)
if err != nil {
logger.Warnf("can not open access log file: %s, %v", fileInfo.Name(), err)
return err
}
}
_, err = logFile.WriteString(accessLogMsg + "\n")
if err != nil {
logger.Warnf("can not write to access log file: %s, v%", fileInfo.Name(), err)
return err
}
return nil
}