Coverage for /var/devmt/py/utils4_1.8.0/utils4/log.py: 100%
37 statements
« prev ^ index » next coverage.py v7.6.9, created at 2025-08-26 21:39 +0100
« prev ^ index » next coverage.py v7.6.9, created at 2025-08-26 21:39 +0100
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:Developer: J Berendt
19:Email: support@s3dev.uk
21:Comments: n/a
23:Example:
25 To use the :class:`~Log` class in your project::
27 >>> from utils4.log import Log
29 >> header = 'COMMENT,TYPE,VAL,UNIT'
30 >> logger = Log(filepath='/tmp/testlog.log',
31 printheader=True,
32 headertext=header)
33 >> logger.write(text='Most cows can jump over the moon,Fact,94.2,pct')
35"""
37import getpass
38import os
39import socket
40from datetime import datetime as dt
43class Log:
44 """This is a small and simple log file creator/writer class.
46 The calling program is responsible for passing the proper arguments
47 to create the log file header. For example::
49 (printheader=True, headertext='some,header,text,here')
51 On class instantiation, validation is performed to determine if the
52 log file exists. If the log file does not exist, a header is
53 required before writing to the log file. These parameters can be passed to
54 the class on instantiation, and will be ignored if the log file already
55 exists.
57 Args:
58 filepath (str): Full path to the log file.
59 autofill (bool, optional): Automatically populate ``datetime.now()``,
60 host and username values, to each log entry. Defaults to True.
61 printheader (bool, optional): Print a log file header using the text
62 passed into the ``headertext`` parameter. Defaults to False.
64 .. note:: The header will only be written if the log file does not
65 exist.
67 headertext (str, optional): String of delimited column labels to be
68 written as the header. Defaults to ''.
69 sep (str, optional): Separator to be used in the log file. This
70 separator is used when writing the autofill values.
71 Defaults to ','.
73 :File Validation:
74 On class instantiation, tests are performed to ensure the log
75 file is being populated in a logical way.
77 * If ``printheader`` is ``False``, and the log file does not
78 exist, the user is notified.
79 * If ``printheader`` is ``True``, yet ``headertext`` is
80 blank, the user is instructed to pass header text.
81 * If ``printheader`` is ``True``, yet the log file already
82 exists, the header will not be written.
84 :Example:
86 To use the :class:`~Log` class in your project::
88 >>> from utils4.log import Log
90 >>> header = 'COMMENT,TYPE,VAL,UNIT'
91 >>> logger = Log(filepath='/tmp/testlog.log',
92 printheader=True,
93 headertext=header)
95 >>> logger.write(text='Most cows can jump over the moon,Fact,94.2,pct')
97 """
99 def __init__(self, filepath, *, autofill=True, printheader=False, headertext='', sep=','):
100 """Log class initialiser."""
101 self._filepath = filepath
102 self._autofill = autofill
103 self._printheader = printheader
104 self._headertext = headertext
105 self._sep = sep
106 self._host = socket.gethostname()
107 self._user = getpass.getuser()
108 self._autotext = ''
109 self._setup()
111 def write(self, text: str):
112 """Write text to the log file defined at instantiation.
114 Args:
115 text (str): Delimited text string to be written to the log.
117 Note:
118 If ``autofill`` is ``True``, the datetime, host and username
119 values **will be populated automatically**; these do *not*
120 need to be passed into the ``text`` argument.
122 :Design:
123 If the ``autofill`` argument is ``True``, the current
124 datetime, host and username values are written (in that
125 order), ahead of the text string provided to the ``text``
126 argument. The ``sep`` parameter (defined at instantiation),
127 is used to separate these auto-populated fields.
129 :Example:
130 To write to the log file::
132 >>> from utils4.log import Log
134 >>> logger = Log(filepath='/tmp/testlog.log, autofill=True)
135 >>> logger.write(text='Just adding some random text to my log')
137 """
138 try:
139 if text:
140 auto_text = f'{dt.now()}{self._sep}{self._autotext}' if self._autofill else ''
141 with open(self._filepath, 'a', encoding='utf-8') as f:
142 f.write(auto_text)
143 f.write(text)
144 f.write('\n')
145 except Exception as err: # pragma: nocover
146 print(err)
148 def write_blank_line(self):
149 """Write a blank line to the log file.
151 Note:
152 The ``autofill`` information is **not** written. This is a
153 true blank line, created by writing the system's native line
154 separator character(s)to the log.
156 :Example:
157 To write a blank line to the log file::
159 >>> from utils4.log import Log
161 >>> logger = Log(filepath='/tmp/testlog.log', autofill=True)
162 >>> logger.write_blank_line()
164 """
165 try:
166 with open(self._filepath, 'a', encoding='utf-8') as f:
167 f.write('\n')
168 except Exception as err: # pragma: nocover
169 print(err)
171 def _setup(self):
172 """Setup tasks performed on class instantiation.
174 :Tasks:
176 - Create the log file.
177 - Write the header.
179 :Validation:
181 - If the log file does not exist, ensure a header is requested.
182 - If the header is requested, ensure the header text is provided.
184 Raised:
185 UserWarning: If either of the validation criteria are not met.
187 """
188 self._autotext = (f'{self._host}{self._sep}{self._user}{self._sep}'
189 if self._autofill else '')
190 # Verify the logfile does not exists, ensure a header is requested.
191 if (not self._printheader) & (not os.path.exists(self._filepath)):
192 raise UserWarning('Header expected, log does not already exist.\n'
193 '- Log file does not exist, therefore a header must be requested,\n'
194 ' as the header is written at the time of log file creation.\n')
195 # Verify header text is populated, if print header is requested.
196 if self._printheader & (not self._headertext):
197 raise UserWarning('Header requested, but header text not received.\n'
198 '- The printheader argument is True, however the headertext string\n'
199 ' is blank. A headertext string must also be supplied.\n')
200 # Write the header if 1) requested, 2) header text provided and 3) log file does not exist.
201 if all([self._printheader, self._headertext, not os.path.exists(self._filepath)]):
202 with open(self._filepath, 'w', encoding='utf-8') as f:
203 f.write(self._headertext)
204 f.write('\n')