Coverage for /var/devmt/py/utils4_1.7.0/utils4/log.py: 100%
37 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-21 20:06 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-21 20:06 +0000
1# -*- coding: utf-8 -*-
2"""
3:Purpose: This is a small class module designed as a central log file
4 creator.
6 The calling program is responsible for passing the proper
7 arguments to create the log file header. For example::
9 (printheader=True, headertext='some,header,text,here')
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.
18:Platform: Linux/Windows | Python 3.7+
19:Developer: J Berendt
20:Email: support@s3dev.uk
22:Comments: n/a
24:Example:
26 To use the :class:`~Log` class in your project::
28 >>> from utils4.log import Log
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')
36"""
38import getpass
39import os
40import socket
41from datetime import datetime as dt
44class Log:
45 """This is a small and simple log file creator/writer class.
47 The calling program is responsible for passing the proper arguments
48 to create the log file header. For example::
50 (printheader=True, headertext='some,header,text,here')
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.
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.
65 .. note:: The header will only be written if the log file does not
66 exist.
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 ','.
74 :File Validation:
75 On class instantiation, tests are performed to ensure the log
76 file is being populated in a logical way.
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.
85 :Example:
87 To use the :class:`~Log` class in your project::
89 >>> from utils4.log import Log
91 >>> header = 'COMMENT,TYPE,VAL,UNIT'
92 >>> logger = Log(filepath='/tmp/testlog.log',
93 printheader=True,
94 headertext=header)
96 >>> logger.write(text='Most cows can jump over the moon,Fact,94.2,pct')
98 """
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()
112 def write(self, text: str):
113 """Write text to the log file defined at instantiation.
115 Args:
116 text (str): Delimited text string to be written to the log.
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.
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.
130 :Example:
131 To write to the log file::
133 >>> from utils4.log import Log
135 >>> logger = Log(filepath='/tmp/testlog.log, autofill=True)
136 >>> logger.write(text='Just adding some random text to my log')
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)
149 def write_blank_line(self):
150 """Write a blank line to the log file.
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.
157 :Example:
158 To write a blank line to the log file::
160 >>> from utils4.log import Log
162 >>> logger = Log(filepath='/tmp/testlog.log', autofill=True)
163 >>> logger.write_blank_line()
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)
172 def _setup(self):
173 """Setup tasks performed on class instantiation.
175 :Tasks:
177 - Create the log file.
178 - Write the header.
180 :Validation:
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.
185 Raised:
186 UserWarning: If either of the validation criteria are not met.
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')