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.
*/
package hwlog
import (
"errors"
"fmt"
"os"
"path"
"regexp"
"strings"
"github.com/fsnotify/fsnotify"
"ascend-common/common-utils/utils"
)
const (
DefaultFileMaxSize = 20
DefaultMinSaveAge = 7
DefaultMaxSaveAge = 700
DefaultMaxBackups = 30
LogFileMode os.FileMode = 0640
BackupLogFileMode os.FileMode = 0400
LogDirMode = 0750
backUpLogRegex = `^.+-[0-9]{4}-[0-9]{2}-[0-9T]{5}-[0-9]{2}-[0-9]{2}\.[0-9]{2,4}`
bitsize = 64
stackDeep = 3
pathLen = 2
minLogLevel = -1
maxLogLevel = 3
maxEachLineLen = 1048576
defaultMaxEachLineLen = 256
)
type LogConfig struct {
LogFileName string
OnlyToStdout bool
OnlyToFile bool
LogLevel int
FileMaxSize int
MaxLineLength int
MaxBackups int
MaxAge int
IsCompress bool
ExpiredTime int
CacheSize int
}
var reg = regexp.MustCompile(backUpLogRegex)
type validateFunc func(config *LogConfig) error
func checkDir(fileDir string) error {
if !utils.IsExist(fileDir) {
if err := os.MkdirAll(fileDir, LogDirMode); err != nil {
return fmt.Errorf("create dirs failed")
}
return nil
}
if err := os.Chmod(fileDir, LogDirMode); err != nil {
return fmt.Errorf("change log dir mode failed")
}
return nil
}
func createFile(filePath string) error {
fileName := path.Base(filePath)
if !utils.IsExist(filePath) {
f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, LogFileMode)
if err != nil {
return fmt.Errorf("create file(%s) failed", fileName)
}
defer func() {
if err := f.Close(); err != nil {
fmt.Printf("close file failed: %v\n", err)
return
}
}()
}
return nil
}
func checkAndCreateLogFile(filePath string) error {
if !utils.IsFile(filePath) {
return fmt.Errorf("config path is not file")
}
fileDir := path.Dir(filePath)
if err := checkDir(fileDir); err != nil {
return err
}
if err := createFile(filePath); err != nil {
return err
}
return nil
}
func validateLogConfigFileMaxSize(config *LogConfig) error {
if config.FileMaxSize == 0 {
config.FileMaxSize = DefaultFileMaxSize
return nil
}
if config.FileMaxSize < 0 || config.FileMaxSize > DefaultFileMaxSize {
return fmt.Errorf("the size of a single log file range is (0, 20] MB")
}
return nil
}
func validateLogConfigBackups(config *LogConfig) error {
if config.MaxBackups <= 0 || config.MaxBackups > DefaultMaxBackups {
return fmt.Errorf("the number of backup log file range is (0, 30]")
}
return nil
}
func validateLogConfigMaxAge(config *LogConfig) error {
if config.MaxAge < DefaultMinSaveAge || config.MaxAge > DefaultMaxSaveAge {
return fmt.Errorf("the maxage of backup logs range is [7,700]")
}
return nil
}
func validateLogLevel(config *LogConfig) error {
if config.LogLevel < minLogLevel || config.LogLevel > maxLogLevel {
return fmt.Errorf("the log level range should be [-1, 3]")
}
return nil
}
func validateMaxLineLength(config *LogConfig) error {
if config.MaxLineLength == 0 {
config.MaxLineLength = defaultMaxEachLineLen
return nil
}
if config.MaxLineLength < 0 || config.MaxLineLength > maxEachLineLen {
return fmt.Errorf("the max length of each log line should be in the range (0, 1048576]")
}
return nil
}
func getValidateFuncList() []validateFunc {
var funcList []validateFunc
funcList = append(funcList, validateLogConfigFileMaxSize, validateLogConfigBackups, validateMaxLineLength,
validateLogConfigMaxAge, validateLogLevel, validateLogConfigLimiter)
return funcList
}
func validateLogConfigFiled(config *LogConfig) error {
if config.OnlyToStdout {
return nil
}
if _, err := utils.CheckPath(config.LogFileName); err != nil && err != os.ErrNotExist {
return fmt.Errorf("config log path is not absolute path: %v", err)
}
if strings.Contains(config.LogFileName, "..") || strings.Contains(config.LogFileName, "./") {
return errors.New("log path include invalid char")
}
if err := checkAndCreateLogFile(config.LogFileName); err != nil {
return err
}
validateFuncList := getValidateFuncList()
for _, vaFunc := range validateFuncList {
if err := vaFunc(config); err != nil {
return err
}
}
return nil
}
func validateLogConfigLimiter(config *LogConfig) error {
if config.ExpiredTime < 0 || config.ExpiredTime > MaxExpiredTime {
return fmt.Errorf("the expired time of log cache range is [0, 3600], the value 0 disables the limiter")
}
if config.CacheSize < 0 || config.CacheSize > MaxCacheSize {
return fmt.Errorf("the size of log cache range is [0, 102400], the value 0 disables the limiter")
}
return nil
}
func changeFileMode(l *logger, event fsnotify.Event, logFileFullPath string) {
if l == nil {
fmt.Println("changeFileMode logger is nil")
return
}
var logMode = LogFileMode
logPath := path.Dir(logFileFullPath)
changedFileName := path.Base(event.Name)
if isTargetLog(changedFileName) {
logMode = BackupLogFileMode
}
changedLogFilePath := path.Join(logPath, changedFileName)
if !utils.IsExist(changedLogFilePath) {
return
}
fPath, err := utils.CheckPath(changedLogFilePath)
if err != nil {
l.Errorf("wrong file path: %v", err)
return
}
if errChmod := os.Chmod(fPath, logMode); errChmod != nil {
l.Errorf("set file mode failed, filename: %s", changedFileName)
}
}
func isTargetLog(fileName string) bool {
return reg.MatchString(fileName)
}