Coverage for /var/devmt/py/utils4_1.5.0rc1/utils4/log.py: 100%

37 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-12 15:38 +0100

1# -*- coding: utf-8 -*- 

2""" 

3:Purpose: This is a small class module designed as a central log file 

4 creator. 

5 

6 The calling program is responsible for passing the proper 

7 arguments to create the log file header. For example:: 

8 

9 (printheader=True, headertext='some,header,text,here') 

10 

11 It is suggested to initialise the :class:`~Log` class 

12 at program startup, with the ``printheader`` parameter 

13 set to ``True``. This is safe because if the log file 

14 already exists, the header will not be re-created. However, 

15 if the log file does not exist, it will be created with a 

16 header, using the value of the ``headertext`` parameter. 

17 

18:Platform: Linux/Windows | Python 3.6+ 

19:Developer: J Berendt 

20:Email: support@s3dev.uk 

21 

22:Comments: n/a 

23 

24:Example: 

25 

26 To use the :class:`~Log` class in your project:: 

27 

28 >>> from utils4.log import Log 

29 

30 >> header = 'COMMENT,TYPE,VAL,UNIT' 

31 >> logger = Log(filepath='/tmp/testlog.log', 

32 printheader=True, 

33 headertext=header) 

34 >> logger.write(text='Most cows can jump over the moon,Fact,94.2,pct') 

35 

36""" 

37 

38import getpass 

39import os 

40import socket 

41from datetime import datetime as dt 

42 

43 

44class Log: 

45 """This is a small and simple log file creator/writer class. 

46 

47 The calling program is responsible for passing the proper arguments 

48 to create the log file header. For example:: 

49 

50 (printheader=True, headertext='some,header,text,here') 

51 

52 On class instantiation, validation is performed to determine if the 

53 log file exists. If the log file does not exist, a header is 

54 required before writing to the log file. These parameters can be passed to 

55 the class on instantiation, and will be ignored if the log file already 

56 exists. 

57 

58 Args: 

59 filepath (str): Full path to the log file. 

60 autofill (bool, optional): Automatically populate ``datetime.now()``, 

61 host and username values, to each log entry. Defaults to True. 

62 printheader (bool, optional): Print a log file header using the text 

63 passed into the ``headertext`` parameter. Defaults to False. 

64 

65 .. note:: The header will only be written if the log file does not 

66 exist. 

67 

68 headertext (str, optional): String of delimited column labels to be 

69 written as the header. Defaults to ''. 

70 sep (str, optional): Separator to be used in the log file. This 

71 separator is used when writing the autofill values. 

72 Defaults to ','. 

73 

74 :File Validation: 

75 On class instantiation, tests are performed to ensure the log 

76 file is being populated in a logical way. 

77 

78 * If ``printheader`` is ``False``, and the log file does not 

79 exist, the user is notified. 

80 * If ``printheader`` is ``True``, yet ``headertext`` is 

81 blank, the user is instructed to pass header text. 

82 * If ``printheader`` is ``True``, yet the log file already 

83 exists, the header will not be written. 

84 

85 :Example: 

86 

87 To use the :class:`~Log` class in your project:: 

88 

89 >>> from utils4.log import Log 

90 

91 >>> header = 'COMMENT,TYPE,VAL,UNIT' 

92 >>> logger = Log(filepath='/tmp/testlog.log', 

93 printheader=True, 

94 headertext=header) 

95 

96 >>> logger.write(text='Most cows can jump over the moon,Fact,94.2,pct') 

97 

98 """ 

99 

100 def __init__(self, filepath, autofill=True, printheader=False, headertext='', sep=','): 

101 """Log class initialiser.""" 

102 self._filepath = filepath 

103 self._autofill = autofill 

104 self._printheader = printheader 

105 self._headertext = headertext 

106 self._sep = sep 

107 self._host = socket.gethostname() 

108 self._user = getpass.getuser() 

109 self._autotext = '' 

110 self._setup() 

111 

112 def write(self, text: str): 

113 """Write text to the log file defined at instantiation. 

114 

115 Args: 

116 text (str): Delimited text string to be written to the log. 

117 

118 Note: 

119 If ``autofill`` is ``True``, the datetime, host and username 

120 values **will be populated automatically**; these do *not* 

121 need to be passed into the ``text`` argument. 

122 

123 :Design: 

124 If the ``autofill`` argument is ``True``, the current 

125 datetime, host and username values are written (in that 

126 order), ahead of the text string provided to the ``text`` 

127 argument. The ``sep`` parameter (defined at instantiation), 

128 is used to separate these auto-populated fields. 

129 

130 :Example: 

131 To write to the log file:: 

132 

133 >>> from utils4.log import Log 

134 

135 >>> logger = Log(filepath='/tmp/testlog.log, autofill=True) 

136 >>> logger.write(text='Just adding some random text to my log') 

137 

138 """ 

139 try: 

140 if text: 

141 auto_text = f'{dt.now()}{self._sep}{self._autotext}' if self._autofill else '' 

142 with open(self._filepath, 'a', encoding='utf-8') as f: 

143 f.write(auto_text) 

144 f.write(text) 

145 f.write('\n') 

146 except Exception as err: # pragma: nocover 

147 print(err) 

148 

149 def write_blank_line(self): 

150 """Write a blank line to the log file. 

151 

152 Note: 

153 The ``autofill`` information is **not** written. This is a 

154 true blank line, created by writing the system's native line 

155 separator character(s)to the log. 

156 

157 :Example: 

158 To write a blank line to the log file:: 

159 

160 >>> from utils4.log import Log 

161 

162 >>> logger = Log(filepath='/tmp/testlog.log', autofill=True) 

163 >>> logger.write_blank_line() 

164 

165 """ 

166 try: 

167 with open(self._filepath, 'a', encoding='utf-8') as f: 

168 f.write('\n') 

169 except Exception as err: # pragma: nocover 

170 print(err) 

171 

172 def _setup(self): 

173 """Setup tasks performed on class instantiation. 

174 

175 :Tasks: 

176 

177 - Create the log file. 

178 - Write the header. 

179 

180 :Validation: 

181 

182 - If the log file does not exist, ensure a header is requested. 

183 - If the header is requested, ensure the header text is provided. 

184 

185 Raised: 

186 UserWarning: If either of the validation criteria are not met. 

187 

188 """ 

189 self._autotext = (f'{self._host}{self._sep}{self._user}{self._sep}' 

190 if self._autofill else '') 

191 # Verify the logfile does not exists, ensure a header is requested. 

192 if (not self._printheader) & (not os.path.exists(self._filepath)): 

193 raise UserWarning('Header expected, log does not already exist.\n' 

194 '- Log file does not exist, therefore a header must be requested,\n' 

195 ' as the header is written at the time of log file creation.\n') 

196 # Verify header text is populated, if print header is requested. 

197 if self._printheader & (not self._headertext): 

198 raise UserWarning('Header requested, but header text not received.\n' 

199 '- The printheader argument is True, however the headertext string\n' 

200 ' is blank. A headertext string must also be supplied.\n') 

201 # Write the header if 1) requested, 2) header text provided and 3) log file does not exist. 

202 if all([self._printheader, self._headertext, not os.path.exists(self._filepath)]): 

203 with open(self._filepath, 'w', encoding='utf-8') as f: 

204 f.write(self._headertext) 

205 f.write('\n')