elog -> evlog
This commit is contained in:
parent
154280cec9
commit
8e23b695bb
16
README.md
16
README.md
@ -1,31 +1,31 @@
|
|||||||
# daily-event-logger
|
# evlog
|
||||||
|
|
||||||
This is a little utility I use for logging my daily activities and events. It is written in Python.
|
This is a little utility I use for logging my daily activities and events. It is written in Python.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m pip install daily-event-logger
|
pipx install evlog
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
To change the directory where elogs are stored, set a shell environment variable ELOG_DIR. To make this change permament, set the following in your shell configuration:
|
To change the directory where evlogs are stored, set a shell environment variable EVLOG_DIR. To make this change permament, set the following in your shell configuration:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export ELOG_DIR="/path/to/elog/dir"
|
export EVLOG_DIR="/path/to/evlog/dir"
|
||||||
```
|
```
|
||||||
|
|
||||||
Otherwise, the default elog directory will be `~/elogs`.
|
Otherwise, the default evlog directory will be `~/evlogs`.
|
||||||
|
|
||||||
To get started, add your first elog entry! This will create a JSON file under your elog directory for the day and ensure the elog directory exists. E.g.:
|
To get started, add your first evlog entry! This will create a JSON file under your evlog directory for the day and ensure the evlog directory exists. E.g.:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
elog add -m "Started new elog. Yay!"
|
evlog add -m "Started new evlog. Yay!"
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
usage: elog [-h] [-v] {add,edit,rm,ls,lsfiles,search} ...
|
usage: evlog [-h] [-v] {add,edit,rm,ls,lsfiles,search} ...
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
{add,edit,rm,ls,lsfiles,search}
|
{add,edit,rm,ls,lsfiles,search}
|
||||||
|
174
evlog.py
174
evlog.py
@ -17,50 +17,50 @@ from rich.traceback import install
|
|||||||
|
|
||||||
install(show_locals=True)
|
install(show_locals=True)
|
||||||
|
|
||||||
VERSION = "0.1.5"
|
VERSION = "0.1.6"
|
||||||
|
|
||||||
default_date = dt.date.today().strftime("%Y-%m-%d")
|
default_date = dt.date.today().strftime("%Y-%m-%d")
|
||||||
ELOG_DIR = os.getenv("ELOG_DIR")
|
EVLOG_DIR = os.getenv("EVLOG_DIR")
|
||||||
if ELOG_DIR is None:
|
if EVLOG_DIR is None:
|
||||||
elog_dir = Path("~/elogs").expanduser()
|
evlog_dir = Path("~/evlogs").expanduser()
|
||||||
else:
|
else:
|
||||||
elog_dir = Path(ELOG_DIR)
|
evlog_dir = Path(EVLOG_DIR)
|
||||||
|
|
||||||
|
|
||||||
def elog_init(filename):
|
def evlog_init(filename):
|
||||||
"""Initialize elog file and directory, if necessary.
|
"""Initialize evlog file and directory, if necessary.
|
||||||
|
|
||||||
elog_dir is taken from the current shell's ELOG_DIR environment variable, or else it defaults to
|
evlog_dir is taken from the current shell's EVLOG_DIR environment variable, or else it defaults to
|
||||||
~/elogs.
|
~/evlogs.
|
||||||
"""
|
"""
|
||||||
elog_file = elog_dir.joinpath(filename).with_suffix(".json")
|
evlog_file = evlog_dir.joinpath(filename).with_suffix(".json")
|
||||||
|
|
||||||
elog_dir.mkdir(exist_ok=True)
|
evlog_dir.mkdir(exist_ok=True)
|
||||||
elog_file.touch()
|
evlog_file.touch()
|
||||||
|
|
||||||
json_array = []
|
json_array = []
|
||||||
|
|
||||||
with open(elog_file, "w") as ef:
|
with open(evlog_file, "w") as ef:
|
||||||
json.dump(json_array, ef)
|
json.dump(json_array, ef)
|
||||||
|
|
||||||
|
|
||||||
def elog_list(args):
|
def evlog_list(args):
|
||||||
"""List elog entries.
|
"""List evlog entries.
|
||||||
|
|
||||||
Lists elog entries for provided timestamp range and/or elog file
|
Lists evlog entries for provided timestamp range and/or evlog file
|
||||||
"""
|
"""
|
||||||
if args.file:
|
if args.file:
|
||||||
selected_elog_file = elog_dir.joinpath(args.file)
|
selected_evlog_file = evlog_dir.joinpath(args.file)
|
||||||
else:
|
else:
|
||||||
selected_elog_file = elog_dir.joinpath(default_date + "_elog").with_suffix(
|
selected_evlog_file = evlog_dir.joinpath(default_date + "_evlog").with_suffix(
|
||||||
".json"
|
".json"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not selected_elog_file.exists():
|
if not selected_evlog_file.exists():
|
||||||
exit("elog file %s not found. Are you sure it exists?" % selected_elog_file)
|
exit("evlog file %s not found. Are you sure it exists?" % selected_evlog_file)
|
||||||
|
|
||||||
if not args.start:
|
if not args.start:
|
||||||
ts_from = selected_elog_file.stem[:10] + " 00:00:00"
|
ts_from = selected_evlog_file.stem[:10] + " 00:00:00"
|
||||||
else:
|
else:
|
||||||
dt.datetime.strptime(args.start, "%Y-%m-%d %H:%M:%S")
|
dt.datetime.strptime(args.start, "%Y-%m-%d %H:%M:%S")
|
||||||
ts_from = args.start
|
ts_from = args.start
|
||||||
@ -71,7 +71,7 @@ def elog_list(args):
|
|||||||
dt.datetime.strptime(args.end, "%Y-%m-%d %H:%M:%S")
|
dt.datetime.strptime(args.end, "%Y-%m-%d %H:%M:%S")
|
||||||
ts_to = args.end
|
ts_to = args.end
|
||||||
|
|
||||||
with open(selected_elog_file, "r") as ef:
|
with open(selected_evlog_file, "r") as ef:
|
||||||
json_data = json.load(ef)
|
json_data = json.load(ef)
|
||||||
|
|
||||||
table = Table(style="#5f00ff", header_style="bold", box=box.ROUNDED)
|
table = Table(style="#5f00ff", header_style="bold", box=box.ROUNDED)
|
||||||
@ -87,12 +87,12 @@ def elog_list(args):
|
|||||||
console.print(table)
|
console.print(table)
|
||||||
|
|
||||||
|
|
||||||
def elog_list_files(args):
|
def evlog_list_files(args):
|
||||||
"""List all elog files.
|
"""List all evlog files.
|
||||||
|
|
||||||
Lists all elog files currently present in elog directory.
|
Lists all evlog files currently present in evlog directory.
|
||||||
"""
|
"""
|
||||||
for file in sorted(elog_dir.iterdir()):
|
for file in sorted(evlog_dir.iterdir()):
|
||||||
if file.is_file():
|
if file.is_file():
|
||||||
if args.absolute:
|
if args.absolute:
|
||||||
print(file)
|
print(file)
|
||||||
@ -100,18 +100,18 @@ def elog_list_files(args):
|
|||||||
print(file.name)
|
print(file.name)
|
||||||
|
|
||||||
|
|
||||||
def elog_search(args):
|
def evlog_search(args):
|
||||||
"""Search for a string.
|
"""Search for a string.
|
||||||
|
|
||||||
Searches all elog files and prints found matches.
|
Searches all evlog files and prints found matches.
|
||||||
"""
|
"""
|
||||||
found_entries = list()
|
found_entries = list()
|
||||||
elog_list = [file.name for file in elog_dir.iterdir()]
|
evlog_list = [file.name for file in evlog_dir.iterdir()]
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
for file in elog_list:
|
for file in evlog_list:
|
||||||
with open(elog_dir.joinpath(file), "r") as ef:
|
with open(evlog_dir.joinpath(file), "r") as ef:
|
||||||
json_data = json.load(ef)
|
json_data = json.load(ef)
|
||||||
for entry in json_data:
|
for entry in json_data:
|
||||||
if args.word in entry["message"]:
|
if args.word in entry["message"]:
|
||||||
@ -126,14 +126,14 @@ def elog_search(args):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
console.print(
|
console.print(
|
||||||
"[bold yellow]{0}[/bold yellow] was not found in any of the elog files".format(
|
"[bold yellow]{0}[/bold yellow] was not found in any of the evlog files".format(
|
||||||
args.word
|
args.word
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def elog_sort(file):
|
def evlog_sort(file):
|
||||||
"""Sort elog entries.
|
"""Sort evlog entries.
|
||||||
|
|
||||||
Entries are sorted by provided timestamp.
|
Entries are sorted by provided timestamp.
|
||||||
"""
|
"""
|
||||||
@ -154,7 +154,7 @@ def validate_json(file):
|
|||||||
|
|
||||||
Call jsonschema.validate on `file`.
|
Call jsonschema.validate on `file`.
|
||||||
"""
|
"""
|
||||||
elog_schema = {
|
evlog_schema = {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"properties": {
|
"properties": {
|
||||||
"timestamp": {"type": "string"},
|
"timestamp": {"type": "string"},
|
||||||
@ -166,17 +166,17 @@ def validate_json(file):
|
|||||||
json_data = json.load(ef)
|
json_data = json.load(ef)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
validate(instance=json_data, schema=elog_schema)
|
validate(instance=json_data, schema=evlog_schema)
|
||||||
except jsonschema.ValidationError as err:
|
except jsonschema.ValidationError as err:
|
||||||
print("Invalid JSON detected on %s" % file)
|
print("Invalid JSON detected on %s" % file)
|
||||||
print(err)
|
print(err)
|
||||||
|
|
||||||
|
|
||||||
def elog_append(args):
|
def evlog_append(args):
|
||||||
"""
|
"""
|
||||||
Append a new elog entry to the elog file.
|
Append a new evlog entry to the evlog file.
|
||||||
|
|
||||||
Use elog file indicated by provided timestamp, or else use the elog file for current day.
|
Use evlog file indicated by provided timestamp, or else use the evlog file for current day.
|
||||||
"""
|
"""
|
||||||
if not args.timestamp:
|
if not args.timestamp:
|
||||||
ts = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
ts = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
@ -184,64 +184,68 @@ def elog_append(args):
|
|||||||
dt.datetime.strptime(args.timestamp, "%Y-%m-%d %H:%M:%S")
|
dt.datetime.strptime(args.timestamp, "%Y-%m-%d %H:%M:%S")
|
||||||
ts = args.timestamp
|
ts = args.timestamp
|
||||||
|
|
||||||
elog_filename = ts[:10] + "_elog"
|
evlog_filename = ts[:10] + "_evlog"
|
||||||
elog_file = elog_dir.joinpath(elog_filename).with_suffix(".json")
|
evlog_file = evlog_dir.joinpath(evlog_filename).with_suffix(".json")
|
||||||
|
|
||||||
if not elog_file.exists():
|
if not evlog_file.exists():
|
||||||
elog_init(elog_file)
|
evlog_init(evlog_file)
|
||||||
|
|
||||||
entry = {"timestamp": ts, "message": args.message}
|
entry = {"timestamp": ts, "message": args.message}
|
||||||
|
|
||||||
with open(elog_file, "r+") as ef:
|
with open(evlog_file, "r+") as ef:
|
||||||
json_data = json.load(ef)
|
json_data = json.load(ef)
|
||||||
json_data.append(entry)
|
json_data.append(entry)
|
||||||
ef.seek(0)
|
ef.seek(0)
|
||||||
json.dump(json_data, ef, indent=4)
|
json.dump(json_data, ef, indent=4)
|
||||||
|
|
||||||
elog_sort(elog_file)
|
evlog_sort(evlog_file)
|
||||||
validate_json(elog_file)
|
validate_json(evlog_file)
|
||||||
|
|
||||||
|
|
||||||
def elog_edit(args):
|
def evlog_edit(args):
|
||||||
"""Edit elog entry at provided index argument."""
|
"""Edit evlog entry at provided index argument."""
|
||||||
if args.file:
|
if args.file:
|
||||||
elog_file = elog_dir.joinpath(args.file)
|
evlog_file = evlog_dir.joinpath(args.file)
|
||||||
else:
|
else:
|
||||||
elog_file = elog_dir.joinpath(default_date + "_elog").with_suffix(".json")
|
evlog_file = evlog_dir.joinpath(default_date + "_evlog").with_suffix(".json")
|
||||||
|
|
||||||
if not elog_file.exists():
|
if not evlog_file.exists():
|
||||||
exit("elog file not found. Please run 'elog append' to start a new elog file.")
|
exit(
|
||||||
|
"evlog file not found. Please run 'evlog append' to start a new evlog file."
|
||||||
|
)
|
||||||
|
|
||||||
with open(elog_file, "r+") as ef:
|
with open(evlog_file, "r+") as ef:
|
||||||
json_data = json.load(ef)
|
json_data = json.load(ef)
|
||||||
json_data[args.index]["message"] = args.message
|
json_data[args.index]["message"] = args.message
|
||||||
ef.seek(0)
|
ef.seek(0)
|
||||||
json.dump(json_data, ef, indent=4)
|
json.dump(json_data, ef, indent=4)
|
||||||
|
|
||||||
validate_json(elog_file)
|
validate_json(evlog_file)
|
||||||
|
|
||||||
|
|
||||||
def elog_remove(args):
|
def evlog_remove(args):
|
||||||
"""Remove an elog entry at provided index argument."""
|
"""Remove an evlog entry at provided index argument."""
|
||||||
if args.file:
|
if args.file:
|
||||||
elog_file = elog_dir.joinpath(args.file)
|
evlog_file = evlog_dir.joinpath(args.file)
|
||||||
else:
|
else:
|
||||||
elog_file = elog_dir.joinpath(default_date + "_elog").with_suffix(".json")
|
evlog_file = evlog_dir.joinpath(default_date + "_evlog").with_suffix(".json")
|
||||||
|
|
||||||
if not elog_file.exists():
|
if not evlog_file.exists():
|
||||||
exit("elog file not found. Please run 'elog append' to start a new elog file.")
|
exit(
|
||||||
|
"evlog file not found. Please run 'evlog append' to start a new evlog file."
|
||||||
|
)
|
||||||
|
|
||||||
with open(elog_file, "r") as ef:
|
with open(evlog_file, "r") as ef:
|
||||||
json_data = json.load(ef)
|
json_data = json.load(ef)
|
||||||
json_data.pop(args.index)
|
json_data.pop(args.index)
|
||||||
|
|
||||||
with open(elog_file, "w") as ef:
|
with open(evlog_file, "w") as ef:
|
||||||
json.dump(json_data, ef, indent=4)
|
json.dump(json_data, ef, indent=4)
|
||||||
|
|
||||||
validate_json(elog_file)
|
validate_json(evlog_file)
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(prog="elog")
|
parser = argparse.ArgumentParser(prog="evlog")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v",
|
"-v",
|
||||||
"--version",
|
"--version",
|
||||||
@ -251,14 +255,14 @@ parser.add_argument(
|
|||||||
)
|
)
|
||||||
subparsers = parser.add_subparsers()
|
subparsers = parser.add_subparsers()
|
||||||
|
|
||||||
add_parser = subparsers.add_parser("add", description="Add an elog entry")
|
add_parser = subparsers.add_parser("add", description="Add an evlog entry")
|
||||||
add_parser.add_argument(
|
add_parser.add_argument(
|
||||||
"-t",
|
"-t",
|
||||||
"--timestamp",
|
"--timestamp",
|
||||||
required=False,
|
required=False,
|
||||||
type=str,
|
type=str,
|
||||||
action="store",
|
action="store",
|
||||||
help="Timestamp for elog entry: str",
|
help="Timestamp for evlog entry: str",
|
||||||
)
|
)
|
||||||
add_parser.add_argument(
|
add_parser.add_argument(
|
||||||
"-m",
|
"-m",
|
||||||
@ -266,18 +270,18 @@ add_parser.add_argument(
|
|||||||
required=True,
|
required=True,
|
||||||
type=str,
|
type=str,
|
||||||
action="store",
|
action="store",
|
||||||
help="Message for elog entry: str",
|
help="Message for evlog entry: str",
|
||||||
)
|
)
|
||||||
add_parser.set_defaults(func=elog_append)
|
add_parser.set_defaults(func=evlog_append)
|
||||||
|
|
||||||
edit_parser = subparsers.add_parser("edit", description="Edit an elog entry")
|
edit_parser = subparsers.add_parser("edit", description="Edit an evlog entry")
|
||||||
edit_parser.add_argument(
|
edit_parser.add_argument(
|
||||||
"-i",
|
"-i",
|
||||||
"--index",
|
"--index",
|
||||||
required=True,
|
required=True,
|
||||||
type=int,
|
type=int,
|
||||||
action="store",
|
action="store",
|
||||||
help="Index of elog entry: int",
|
help="Index of evlog entry: int",
|
||||||
)
|
)
|
||||||
edit_parser.add_argument(
|
edit_parser.add_argument(
|
||||||
"-m",
|
"-m",
|
||||||
@ -285,7 +289,7 @@ edit_parser.add_argument(
|
|||||||
required=True,
|
required=True,
|
||||||
type=str,
|
type=str,
|
||||||
action="store",
|
action="store",
|
||||||
help="New message for elog entry: str",
|
help="New message for evlog entry: str",
|
||||||
)
|
)
|
||||||
edit_parser.add_argument(
|
edit_parser.add_argument(
|
||||||
"-f",
|
"-f",
|
||||||
@ -293,18 +297,18 @@ edit_parser.add_argument(
|
|||||||
required=False,
|
required=False,
|
||||||
type=str,
|
type=str,
|
||||||
action="store",
|
action="store",
|
||||||
help="elog file to edit. Ex: 2022-10-02_elog.json",
|
help="evlog file to edit. Ex: 2022-10-02_evlog.json",
|
||||||
)
|
)
|
||||||
edit_parser.set_defaults(func=elog_edit)
|
edit_parser.set_defaults(func=evlog_edit)
|
||||||
|
|
||||||
rm_parser = subparsers.add_parser("rm", description="Remove an elog entry")
|
rm_parser = subparsers.add_parser("rm", description="Remove an evlog entry")
|
||||||
rm_parser.add_argument(
|
rm_parser.add_argument(
|
||||||
"-i",
|
"-i",
|
||||||
"--index",
|
"--index",
|
||||||
required=True,
|
required=True,
|
||||||
type=int,
|
type=int,
|
||||||
action="store",
|
action="store",
|
||||||
help="Index of elog entry: int",
|
help="Index of evlog entry: int",
|
||||||
)
|
)
|
||||||
rm_parser.add_argument(
|
rm_parser.add_argument(
|
||||||
"-f",
|
"-f",
|
||||||
@ -312,11 +316,11 @@ rm_parser.add_argument(
|
|||||||
required=False,
|
required=False,
|
||||||
type=str,
|
type=str,
|
||||||
action="store",
|
action="store",
|
||||||
help="elog file to remove from. Ex: 2022-10-02_elog.json",
|
help="evlog file to remove from. Ex: 2022-10-02_evlog.json",
|
||||||
)
|
)
|
||||||
rm_parser.set_defaults(func=elog_remove)
|
rm_parser.set_defaults(func=evlog_remove)
|
||||||
|
|
||||||
ls_parser = subparsers.add_parser("ls", description="List elog entries")
|
ls_parser = subparsers.add_parser("ls", description="List evlog entries")
|
||||||
ls_parser.add_argument(
|
ls_parser.add_argument(
|
||||||
"-s",
|
"-s",
|
||||||
"--start",
|
"--start",
|
||||||
@ -341,27 +345,27 @@ ls_parser.add_argument(
|
|||||||
required=False,
|
required=False,
|
||||||
type=str,
|
type=str,
|
||||||
action="store",
|
action="store",
|
||||||
help="elog file to view. Ex: 2022-10-02_elog.json",
|
help="evlog file to view. Ex: 2022-10-02_evlog.json",
|
||||||
)
|
)
|
||||||
ls_parser.set_defaults(func=elog_list)
|
ls_parser.set_defaults(func=evlog_list)
|
||||||
|
|
||||||
ls_files_parser = subparsers.add_parser("lsfiles", description="List all elog files")
|
ls_files_parser = subparsers.add_parser("lsfiles", description="List all evlog files")
|
||||||
ls_files_parser.add_argument(
|
ls_files_parser.add_argument(
|
||||||
"-a",
|
"-a",
|
||||||
"--absolute",
|
"--absolute",
|
||||||
required=False,
|
required=False,
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="List the absolute paths of the elog files",
|
help="List the absolute paths of the evlog files",
|
||||||
)
|
)
|
||||||
ls_files_parser.set_defaults(func=elog_list_files)
|
ls_files_parser.set_defaults(func=evlog_list_files)
|
||||||
|
|
||||||
search_parser = subparsers.add_parser(
|
search_parser = subparsers.add_parser(
|
||||||
"search", description="Search for keywords in elog files"
|
"search", description="Search for keywords in evlog files"
|
||||||
)
|
)
|
||||||
search_parser.add_argument(
|
search_parser.add_argument(
|
||||||
"-w", "--word", required=True, type=str, action="store", help="Word to search for"
|
"-w", "--word", required=True, type=str, action="store", help="Word to search for"
|
||||||
)
|
)
|
||||||
search_parser.set_defaults(func=elog_search)
|
search_parser.set_defaults(func=evlog_search)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "evlog"
|
name = "evlog"
|
||||||
version = "0.1.5"
|
version = "0.1.6"
|
||||||
authors = [
|
authors = [
|
||||||
{ name="Jeffrey Serio", email="hyperreal@moonshadow.dev" },
|
{ name="Jeffrey Serio", email="hyperreal@moonshadow.dev" },
|
||||||
]
|
]
|
||||||
@ -18,8 +18,8 @@ dependencies = ["jsonschema>=4.17.0", "rich>=12.6.0"]
|
|||||||
elog = "evlog:main"
|
elog = "evlog:main"
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Homepage = "https://git.hyperreal.coffee/hyperreal/daily-event-logger"
|
Homepage = "https://git.hyperreal.coffee/hyperreal/evlog"
|
||||||
Issues = "https://git.hyperreal.coffee/hyperreal/daily-event-logger/issues"
|
Issues = "https://git.hyperreal.coffee/hyperreal/evlog/issues"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user