PK pFQZ: mklog/__init__.py# Copyright 2009-2015 Louis Paternault
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
"""Some meta-information about mklog."""
VERSION = "0.3.3"
PK x0Fؑ" mklog/errors.py# Copyright Louis Paternault 2011-2015
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see . 1
"""Errors and exceptions"""
class MklogError(Exception):
"""Generic error for mklog"""
pass
class ExecutionError(MklogError):
"""Error while running user command"""
def __init__(self, message):
super().__init__()
self.message = message
def __str__(self):
return "Error when running '{}'.".format(" ".join(self.message))
PK 9Hڕ$ $
mklog/main.py# Copyright 2009-2015 Louis Paternault
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
"""Simple way of logging things.
* "Logging" means prepending date and time at the beginning of lines.
* "Things" may be content of files, standard input, or output of a command.
"""
from collections import namedtuple
import argparse
import io
import logging
import os
import subprocess
import sys
import textwrap
import threading
import time
import mklog
from mklog import errors
LOGGER = logging.getLogger(mklog.__name__)
LOGGER.addHandler(logging.StreamHandler())
TIMEFORMAT = "%Y-%m-%d %H:%M:%S"
################################################################################
##### Print line preceded by date and time
# No verification is done whether argument contains exactly one line or not.
def log(line, output_format, error=False):
r"""Print argument to standard output, preceded by current time and date
Arguments:
- error: if True, print it to standard error, in standard output otherwise.
- line: a string to print, supposed to end with an EOL character (\n).
- output_format: a named tuple of two strings.
- output_format.line is the line-format. It can (should?) contain
substrings as "{time}" and "{output}" which are replaced by current
time and the line to print.
- output_format.time is the time-format. It will be passed to
"time.strftime()" to print current time.
"""
if error:
out = sys.stderr
else:
out = sys.stdout
out.write(output_format.line.format(
time=time.strftime(output_format.time),
output=line[:-1],
))
out.write("\n")
out.flush()
def log_fd(file_desc, output_format, error=False):
"""Print content from `file_desc`, preceding it by current date and time.
:param int file_desc: File descriptor to read from.
:param str output_format: format to use to print content. See :func:`log`
to know its syntax.
:param bool error: If `True`, print it to standard error, and in standard
output otherwise.
"""
with os.fdopen(file_desc, errors="replace") as file:
log_file(file, output_format, error)
def log_file(file, output_format, error=False):
"""Print content from :class:`file` `file`, preceding it by current date and time.
Except from `file`, arguments are the same as arguments of :func:`log_fd`.
"""
for line in file:
log(line, output_format, error)
################################################################################
def safe_open(name):
"""Safely open a file, and return
- None if an error occured
- The file object otherwise"""
try:
return open(name, 'r', errors="replace")
except IOError:
LOGGER.error("Error while opening '%s'.", name)
return None
################################################################################
### Parsing arguments
def commandline_parser():
"""Parse command line
Return a tuple (options, file), where:
- options: a dictionary containing only the command (if any) to be executed
(corresponding to option "-c") in the key "command";
- file: the list of files to be processed.
"""
# Defining parser
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter,
description=textwrap.dedent("""
Print the standard input, content of files, or result of a command
to standard output, preceded by date and time (in a log-like way).
"""),
epilog=textwrap.dedent("""
`mklog` aims to be a simple way to write text in a log format,
i.e. each line being preceded by date and time it was written.
Text can be either standard input, content of files, or both
standard and error output of a command.
If neither files nor a command are given, standard input is
processed. Otherwise, the content of each file (if any), and the
output of the command (if any) are processed.
# Environment
When executing command (with `-c` option), environment is
preserved, and command should run exactly the same way it should
have run if it had been executed directly within the shell.
"""),
)
parser.add_argument(
'--version',
action='version',
version="%(prog)s {version}".format(
version=mklog.VERSION,
),
)
parser.add_argument(
"files",
metavar="FILES",
nargs='*',
help="Files to process.",
)
parser.add_argument(
"-f", "--format",
dest="line_format",
default="{time} {output}",
help=textwrap.dedent("""\
Format of output. Interpreted sequences are "{time}" for current
time, "{output}" for output of the command. Default is "{time}
{output}".
"""),
)
parser.add_argument(
"-t", "--time-format",
dest="time_format",
default=TIMEFORMAT,
help=textwrap.dedent("""\
Format of time. See the "time" documentation for more information
about format (e.g.
http://docs.python.org/library/time.html#time.strftime). Default
is "{}".
""".format(TIMEFORMAT.replace('%', '%%'))),
)
parser.add_argument(
"-c", "--command",
nargs=argparse.REMAINDER,
help=textwrap.dedent("""
Run command, processing both its standard and error output.
Commands can be written whithout quotes (such as `mklog -c tail -f
file1 file2`), or with it, which allows using shell features (such
as `mklog -c "(ls; cat file1) & cat file2"`).
Destination of output is preserved: standard output of command is
written to standard output of `mklog`, and standard error to
standard error. Both are processed.
This must be the last option on the command line.
"""),
)
# Running parser
return parser
################################################################################
### Main function
def main():
"Main function"
options = commandline_parser().parse_args()
# Now, "options" contains a dictionary containing only the command (if any)
# to be executed (corresponding to option "-c") in the key "command", and
# "files" contains the list of files to be processed.
try:
# Handling files
# At the end of this block, "files" will contain the list of files to
# be read from: either files given in argument, or standard input if no
# file is given in the command line.
if len(options.files) == 0 and options.command == None:
options.files = [io.TextIOWrapper(
sys.stdin.buffer,
encoding=sys.stdin.encoding,
errors="replace"
)]
else:
options.files = [safe_open(f) for f in options.files]
# Processing "options.line_format" and "options.time_format".
# Quick and dirty parsing.
output_format = namedtuple("Format", "line, time")(
line=options.line_format,
time=options.time_format,
)
# Processing files
for file_descriptor in options.files:
if file_descriptor is None:
continue
log_file(file_descriptor, output_format)
# Handling command
if options.command != None:
stdout = os.pipe()
stderr = os.pipe()
try:
process = subprocess.Popen(
options.command,
stdin=sys.stdin,
stdout=stdout[1],
stderr=stderr[1],
shell=(len(options.command) == 1),
)
except OSError:
raise errors.ExecutionError(options.command)
standard = [
threading.Thread(
target=log_fd,
kwargs={
'file_desc' : pipe[0],
'output_format': output_format
},
daemon=True,
)
for pipe in [stdout, stderr]
]
for thread in standard:
thread.start()
process.wait()
os.close(stderr[1])
os.close(stdout[1])
for thread in standard:
thread.join()
except KeyboardInterrupt:
sys.exit(1)
except errors.MklogError as error:
LOGGER.error(error)
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()
PK ۳9H;k k % mklog-0.3.3.dist-info/DESCRIPTION.rstmklog — Convert any output into a log (date and time prepended to each line)
============================================================================
|sources| |documentation| |pypi| |license|
`mklog` is a python program that converts standard input, content of files, or
output of a command in a log-like format, i.e. current date and time is
prepended to each line.
Run `mklog --help` for the list of available options; see examples below.
Example
-------
Download using wget::
$ mklog -c wget https://archive.org/download/Popeye_Nearlyweds/Popeye_Nearlyweds.ogv
2015-02-05 13:13:41 --2015-02-05 13:13:41-- http://t/
2015-02-05 13:13:41 Résolution de t (t)… échec : Nom ou service inconnu.
2015-02-05 13:13:41 wget : impossible de résoudre l'adresse de l'hôte « t »
2015-02-05 13:13:41 --2015-02-05 13:13:41-- https://archive.org/download/Popeye_Nearlyweds/Popeye_Nearlyweds.ogv
2015-02-05 13:13:41 Résolution de archive.org (archive.org)… 207.241.224.2
2015-02-05 13:13:41 Connexion à archive.org (archive.org)|207.241.224.2|:443… connecté.
2015-02-05 13:13:42 requête HTTP transmise, en attente de la réponse… 302 Moved Temporarily
2015-02-05 13:13:42 Emplacement : https://ia700502.us.archive.org/6/items/Popeye_Nearlyweds/Popeye_Nearlyweds.ogv [suivant]
2015-02-05 13:13:42 --2015-02-05 13:13:42-- https://ia700502.us.archive.org/6/items/Popeye_Nearlyweds/Popeye_Nearlyweds.ogv
2015-02-05 13:13:42 Résolution de ia700502.us.archive.org (ia700502.us.archive.org)… 207.241.237.122
2015-02-05 13:13:42 Connexion à ia700502.us.archive.org (ia700502.us.archive.org)|207.241.237.122|:443… connecté.
2015-02-05 13:13:43 requête HTTP transmise, en attente de la réponse… 200 OK
2015-02-05 13:13:43 Taille : 26698780 (25M) [video/ogg]
2015-02-05 13:13:43 Sauvegarde en : « Popeye_Nearlyweds.ogv »
2015-02-05 13:13:43
2015-02-05 13:13:44 0K .......... .......... .......... .......... .......... 0% 126K 3m26s
[...]
2015-02-05 13:14:18 26000K .......... .......... .......... .......... .......... 99% 541K 0s
2015-02-05 13:14:18 26050K .......... .......... ... 100% 5,80M=34s
2015-02-05 13:14:18
2015-02-05 13:14:18 2015-02-05 13:14:18 (762 KB/s) — « Popeye_Nearlyweds.ogv » sauvegardé [26698780/26698780]
2015-02-05 13:14:18
2015-02-05 13:14:18 Terminé — 2015-02-05 13:14:18 —
2015-02-05 13:14:18 Temps total effectif : 37s
2015-02-05 13:14:18 Téléchargés : 1 fichiers, 25M en 34s (762 KB/s)
Monitor logs (which are not dated)::
$ tail -f /var/log/gdm3/\:0.log | mklog
What's new?
-----------
See `changelog
`_.
Download and install
--------------------
See the end of list for a (quick and dirty) Debian package.
* From sources:
* Download: https://pypi.python.org/pypi/mklog
* Install (in a `virtualenv`, not to mess with your distribution installation system)::
python3 setup.py install
* With pip::
pip install mklog
* Quick and dirty Debian (and Ubuntu?) package
This requires `stdeb `_ to be installed::
python3 setup.py --command-packages=stdeb.command bdist_deb
sudo dpkg -i deb_dist/mklog-_all.deb
See also
--------
See also (other program with the same purpose):
* `ts `_
.. |documentation| image:: http://readthedocs.org/projects/mklog/badge
:target: http://mklog.readthedocs.org
.. |pypi| image:: https://img.shields.io/pypi/v/mklog.svg
:target: http://pypi.python.org/pypi/mklog
.. |license| image:: https://img.shields.io/pypi/l/mklog.svg
:target: http://www.gnu.org/licenses/gpl-3.0.html
.. |sources| image:: https://img.shields.io/badge/sources-mklog-brightgreen.svg
:target: http://git.framasoft.org/spalax/mklog
PK ҳ9Hk2J+ + &