399 lines
13 KiB
Python
Executable File
399 lines
13 KiB
Python
Executable File
# -*- coding:utf-8 -*-
|
|
#############################################################################
|
|
# Portions Copyright (c) 2022 Huawei Technologies Co.,Ltd.
|
|
#
|
|
# openGauss is licensed under Mulan PSL v2.
|
|
# You can use this software according to the terms
|
|
# and conditions of the Mulan PSL v2.
|
|
# You may obtain a copy of Mulan PSL v2 at:
|
|
#
|
|
# http://license.coscl.org.cn/MulanPSL2
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OF ANY KIND,
|
|
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
# See the Mulan PSL v2 for more details.
|
|
# ----------------------------------------------------------------------------
|
|
# Description : CMLog.py is utility to handle the log
|
|
#############################################################################
|
|
import os
|
|
import sys
|
|
import datetime
|
|
import subprocess
|
|
import _thread as thread
|
|
import re
|
|
import logging.handlers as _handlers
|
|
import time
|
|
|
|
sys.path.append(sys.path[0] + "/../../")
|
|
|
|
from ErrorCode import ErrorCode
|
|
|
|
# import typing for comment.
|
|
try:
|
|
from typing import Dict
|
|
from typing import List
|
|
except ImportError:
|
|
Dict = dict
|
|
List = list
|
|
|
|
# max log file size
|
|
# 16M
|
|
MAXLOGFILESIZE = 16 * 1024 * 1024
|
|
|
|
LOG_DEBUG = 1
|
|
LOG_INFO = 2
|
|
LOG_WARNING = 2.1
|
|
LOG_ERROR = 3
|
|
LOG_FATAL = 4
|
|
|
|
|
|
class CMLog:
|
|
"""
|
|
Class to handle log file
|
|
"""
|
|
|
|
def __init__(self, logPath, module, prefix, suffix = ".log", expectLevel=LOG_DEBUG, traceId=None):
|
|
"""
|
|
function: Constructor
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
self.logFile = ""
|
|
self.expectLevel = expectLevel
|
|
self.moduleName = module
|
|
self.fp = None
|
|
self.size = 0
|
|
self.suffix = suffix
|
|
self.prefix = prefix
|
|
self.logPath = logPath
|
|
self.pid = os.getpid()
|
|
self.step = 0
|
|
self.lock = thread.allocate_lock()
|
|
self.tmpFile = None
|
|
self.ignoreErr = False
|
|
self.traceId = traceId
|
|
|
|
try:
|
|
if not os.path.isdir(logPath):
|
|
print(ErrorCode.GAUSS_502["GAUSS_50211"] % logPath)
|
|
sys.exit(1)
|
|
# check log path
|
|
if not os.path.exists(logPath):
|
|
try:
|
|
os.makedirs(logPath, 0o700)
|
|
except Exception as e:
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50208"] %
|
|
logPath + " Error:\n%s" % str(e))
|
|
# create new log file
|
|
self.__openLogFile()
|
|
except Exception as ex:
|
|
print(str(ex))
|
|
sys.exit(1)
|
|
|
|
def __checkLink(self):
|
|
"""
|
|
function: check log file is link
|
|
input : NA
|
|
output: list of
|
|
"""
|
|
if os.path.islink(self.logFile):
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50206"] % self.logFile)
|
|
|
|
def __checkLogFileExist(self):
|
|
"""
|
|
check whether log file exists, if exist, get log file name
|
|
log file name format:
|
|
prefix-YYYY-mm-DD_HHMMSSsuffix = cm_install-YYYY-mm-DD_HHMMSS.log
|
|
"""
|
|
logFileList = "%s/logFileList_%s.dat" % (self.logPath, self.pid)
|
|
cmd = "ls %s | grep '^%s-.*%s$' > %s" % (
|
|
self.logPath, self.prefix, self.suffix, logFileList)
|
|
(status, output) = subprocess.getstatusoutput(cmd)
|
|
if status != 0:
|
|
if os.path.exists(logFileList):
|
|
os.remove(logFileList)
|
|
return False
|
|
with open(logFileList, "r") as fp:
|
|
filenameList = []
|
|
while True:
|
|
# get real file name
|
|
filename = (fp.readline()).strip()
|
|
if not filename:
|
|
break
|
|
existedResList = filename.split(".")
|
|
if len(existedResList) > 2:
|
|
continue
|
|
(existedPrefix, existedSuffix) = \
|
|
os.path.splitext(filename)
|
|
if existedSuffix != self.suffix:
|
|
continue
|
|
if len(filename) != len(self.prefix) + \
|
|
len(self.suffix) + 18:
|
|
continue
|
|
timeStamp = existedPrefix[-17:]
|
|
# check log file name
|
|
if self.__isValidDate(timeStamp):
|
|
filenameList.append(filename)
|
|
# cleanup logFileList
|
|
if os.path.exists(logFileList):
|
|
os.remove(logFileList)
|
|
|
|
if len(filenameList) == 0:
|
|
return False
|
|
# get logFile
|
|
fileName = max(filenameList)
|
|
self.logFile = os.path.join(self.logPath, fileName)
|
|
self.__checkLink()
|
|
return True
|
|
|
|
def __openLogFile(self):
|
|
"""
|
|
function: open log file
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
try:
|
|
if self.__checkLogFileExist():
|
|
self.fp = open(self.logFile, "a")
|
|
return
|
|
# get current time
|
|
currentTime = time.strftime("%Y-%m-%d_%H%M%S")
|
|
# init log file
|
|
self.logFile = os.path.join(self.logPath, self.prefix + "-" + currentTime + self.suffix)
|
|
# Re-create the log file to add a retry 3 times mechanism,
|
|
# in order to call concurrently between multiple processes
|
|
retryTimes = 3
|
|
count = 0
|
|
while (True):
|
|
(status, output) = self.__createLogFile()
|
|
if status == 0:
|
|
break
|
|
count = count + 1
|
|
time.sleep(1)
|
|
if (count > retryTimes):
|
|
raise Exception(output)
|
|
# open log file
|
|
self.__checkLink()
|
|
self.fp = open(self.logFile, "a")
|
|
except Exception as e:
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50206"]
|
|
% self.logFile + " Error:\n%s" % str(e))
|
|
|
|
def __createLogFile(self):
|
|
"""
|
|
function: create log file
|
|
input : NA
|
|
output: (status, output)
|
|
"""
|
|
try:
|
|
if (not os.path.exists(self.logFile)):
|
|
os.mknod(self.logFile)
|
|
return (0, "")
|
|
except Exception as e:
|
|
return (1, str(e))
|
|
|
|
def __isValidDate(self, datastr):
|
|
"""
|
|
function: Judge if date valid
|
|
input : datastr
|
|
output: bool
|
|
"""
|
|
try:
|
|
time.strptime(datastr, "%Y-%m-%d_%H%M%S")
|
|
return True
|
|
except Exception as ex:
|
|
return False
|
|
|
|
def closeLog(self):
|
|
"""
|
|
function: Function to close log file
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
try:
|
|
if self.fp:
|
|
self.fp.flush()
|
|
self.fp.close()
|
|
self.fp = None
|
|
except Exception as ex:
|
|
if self.fp:
|
|
self.fp.close()
|
|
raise Exception(str(ex))
|
|
|
|
# print the flow message to console window and log file
|
|
# AddInfo: constant represent step constant, addStep represent step
|
|
# plus, None represent no step
|
|
def log(self, msg, stepFlag=""):
|
|
"""
|
|
function:print the flow message to console window and log file
|
|
input: msg,stepFlag
|
|
control: when stepFlag="", the OM background log does not display
|
|
step information.
|
|
when stepFlag="addStep", the OM background log step will
|
|
add 1.
|
|
when stepFlag="constant", the OM background log step
|
|
defaults to the current step.
|
|
output: NA
|
|
"""
|
|
if (LOG_INFO >= self.expectLevel):
|
|
print(msg)
|
|
self.__writeLog("LOG", msg, stepFlag)
|
|
|
|
# print the flow message to log file only
|
|
def debug(self, msg, stepFlag=""):
|
|
"""
|
|
function:print the flow message to log file only
|
|
input: msg,stepFlag
|
|
control: when stepFlag="", the OM background log does not display
|
|
step information.
|
|
when stepFlag="addStep", the OM background log step will
|
|
add 1.
|
|
when stepFlag="constant", the OM background log step
|
|
defaults to the current step.
|
|
output: NA
|
|
"""
|
|
if (LOG_DEBUG >= self.expectLevel):
|
|
self.__writeLog("DEBUG", msg, stepFlag)
|
|
|
|
def warn(self, msg, stepFlag=""):
|
|
"""
|
|
function:print the flow message to log file only
|
|
input: msg,stepFlag
|
|
control: when stepFlag="", the OM background log does not display
|
|
step information.
|
|
when stepFlag="addStep", the OM background log step will
|
|
add 1.
|
|
when stepFlag="constant", the OM background log step
|
|
defaults to the current step.
|
|
output: NA
|
|
"""
|
|
if (LOG_WARNING >= self.expectLevel):
|
|
print(msg)
|
|
self.__writeLog("WARNING", msg, stepFlag)
|
|
|
|
# print the error message to console window and log file
|
|
def error(self, msg):
|
|
"""
|
|
function: print the error message to console window and log file
|
|
input : msg
|
|
output: NA
|
|
"""
|
|
if (LOG_ERROR >= self.expectLevel):
|
|
print(msg)
|
|
self.__writeLog("ERROR", msg)
|
|
|
|
# print the error message to console window and log file,then exit
|
|
def logExit(self, msg):
|
|
"""
|
|
function: print the error message to console window and log file,
|
|
then exit
|
|
input : msg
|
|
output: NA
|
|
"""
|
|
if (LOG_FATAL >= self.expectLevel):
|
|
print(msg)
|
|
try:
|
|
self.__writeLog("ERROR", msg)
|
|
except Exception as ex:
|
|
print(str(ex))
|
|
self.closeLog()
|
|
sys.exit(1)
|
|
|
|
def Step(self, stepFlag):
|
|
"""
|
|
function: return Step number info
|
|
input: add
|
|
output: step number
|
|
"""
|
|
if (stepFlag == "constant"):
|
|
return self.step
|
|
else:
|
|
self.step = self.step + 1
|
|
return self.step
|
|
|
|
def __getLogFileLine(self):
|
|
f = sys._getframe().f_back.f_back.f_back
|
|
return "%s(%s:%s)" % (os.path.basename(f.f_code.co_filename), f.f_code.co_name,
|
|
str(f.f_lineno))
|
|
|
|
def __writeLog(self, level, msg, stepFlag=""):
|
|
"""
|
|
function: Write log to file
|
|
input: level, msg, stepFlag
|
|
output: NA
|
|
"""
|
|
if self.fp is None:
|
|
return
|
|
|
|
try:
|
|
self.lock.acquire()
|
|
# if the log file does not exits, create it
|
|
if (not os.path.exists(self.logFile)):
|
|
self.__openLogFile()
|
|
else:
|
|
logPer = oct(os.stat(self.logFile).st_mode)[-3:]
|
|
self.__checkLink()
|
|
if not logPer == "600":
|
|
os.chmod(self.logFile, 0o600)
|
|
# check if need switch to an new log file
|
|
self.size = os.path.getsize(self.logFile)
|
|
if self.size >= MAXLOGFILESIZE and os.getuid() != 0:
|
|
self.closeLog()
|
|
self.__openLogFile()
|
|
|
|
replaceReg = re.compile(r'-W[ ]*[^ ]*[ ]*')
|
|
msg = replaceReg.sub('-W *** ', str(msg))
|
|
|
|
if msg.find("gs_redis") >= 0:
|
|
replaceReg = re.compile(r'-A[ ]*[^ ]*[ ]*')
|
|
msg = replaceReg.sub('-A *** ', str(msg))
|
|
|
|
strTime = datetime.datetime.now()
|
|
fileLine = self.__getLogFileLine()
|
|
if stepFlag == "":
|
|
if self.traceId:
|
|
print("[%s][%s][%d][%s][%s]:%s"
|
|
% (self.traceId, strTime, self.pid, self.moduleName,
|
|
level, msg), file=self.fp)
|
|
else:
|
|
print("[%s][%d][%s][%s]:%s" % (
|
|
strTime, self.pid, self.moduleName, level, msg),
|
|
file=self.fp)
|
|
else:
|
|
stepnum = self.Step(stepFlag)
|
|
print("[%s][%d][%s][%s][%s][Step%d]:%s" % (
|
|
strTime, self.pid, fileLine, self.moduleName, level, stepnum, msg),
|
|
file=self.fp)
|
|
self.fp.flush()
|
|
self.lock.release()
|
|
except Exception as ex:
|
|
self.lock.release()
|
|
if self.ignoreErr:
|
|
return
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50205"]
|
|
% (("log file %s") % self.logFile) +
|
|
" Error:\n%s" % str(ex))
|
|
|
|
@staticmethod
|
|
def exitWithError(msg, status=1):
|
|
"""
|
|
function: Exit with error message
|
|
input: msg, status=1
|
|
output: NA
|
|
"""
|
|
sys.stderr.write("%s\n" % msg)
|
|
sys.exit(status)
|
|
|
|
@staticmethod
|
|
def printMessage(msg):
|
|
"""
|
|
function: Print the String message
|
|
input: msg
|
|
output: NA
|
|
"""
|
|
sys.stdout.write("%s\n" % msg)
|
|
|
|
|