Skip to content

Commit

Permalink
move logging logic to its own module (#910)
Browse files Browse the repository at this point in the history
* move logging logic to its own module

* add log-setting functions, documentation
  • Loading branch information
oscarlevin authored Feb 4, 2025
1 parent d0afbb9 commit f4ed272
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 36 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ Instructions: Add a subsection under `[Unreleased]` for additions, fixes, change

## [Unreleased]

### Added

- Logging is now available when the CLI is used programmatically (as a library). See [docs/api.md](docs/api.md).

### Changed

- Asset generation of asymptote, latex-image, and sageplot now utilize a *generated-cache* of images (stored in `.generated-cache` in the root of a project, but customizable in `project.ptx`). This should speed up building and generating assets.
- Asset generation of asymptote, latex-image, and sageplot now utilize a *generated-cache* of images (stored in `.cache` in the root of a project, but customizable in `project.ptx`). This should speed up building and generating assets.

## [2.12.0] - 2025-01-16

Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ Similarly, `entities.ent` may be used:

_Note: previously this was achieved with a `pretext-href` attribute - this is now deprecated and will be removed in a future release._

---
## Using this package as a library/API

We have started documenting how you can use this CLI programmatically in [docs/api.md](docs/api.md).

---

## Development
Expand Down Expand Up @@ -212,7 +217,7 @@ poetry shell
pretext --version # returns version being developed
```
When inside a `poetry shell` you can navegate to other folders and run pretext commands. Doing so will use the current development environment version of pretext.
When inside a `poetry shell` you can navigate to other folders and run pretext commands. Doing so will use the current development environment version of pretext.
### Updating dependencies
Expand Down
24 changes: 24 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Using PreTeXt as a library

The PreTeXt-CLI includes `Project` and `Target` classes which can be used when this package is imported as a library.

More details are coming soon.

## Logging

This package uses python's logging library and implements a logger with name `"ptxlogger"`. To get the same messages as the CLI gives (with default level of `INFO`), you can include the following.

```python
import logging
from pretext import logger

log = logging.getLogger("ptxlogger")
logger.add_log_stream_handler()
log.setLevel(logging.INFO)
```

The `logger.add_log_stream_handler()` function simply creates a stream-handler that outputs to stdout. You could set up `log` however you like using the options provided by the `logging` library. If you would like to get spit out the logs to a file as the CLI does, you could include the line

```python
logger.add_log_file_handler(path_to_log_directory)
```
3 changes: 0 additions & 3 deletions pretext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import logging
from pathlib import Path
from single_version import get_version

log = logging.getLogger("ptxlogger")

VERSION = get_version("pretext", Path(__file__).parent.parent)

CORE_COMMIT = "3ce0b18284473f5adf52cea46374688299b6d643"
Expand Down
35 changes: 4 additions & 31 deletions pretext/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import click
import click_log
import shutil
import datetime
import os
import zipfile
import requests
Expand All @@ -23,34 +22,18 @@
utils,
resources,
constants,
logger,
plastex,
server,
VERSION,
CORE_COMMIT,
)


from .project import Project

log = logging.getLogger("ptxlogger")

# click_handler logs all messages to stdout as the CLI runs
click_handler = logging.StreamHandler(sys.stdout)
click_handler.setFormatter(click_log.ColorFormatter())
log.addHandler(click_handler)

# error_flush_handler captures error/critical logs for flushing to stderr at the end of a CLI run
sh = logging.StreamHandler(sys.stderr)
sh.setFormatter(click_log.ColorFormatter())
sh.setLevel(logging.ERROR)
error_flush_handler = logging.handlers.MemoryHandler(
capacity=1024 * 100,
flushLevel=100,
target=sh,
flushOnClose=False,
)
error_flush_handler.setLevel(logging.ERROR)
log.addHandler(error_flush_handler)
logger.add_log_stream_handler()
error_flush_handler = logger.get_log_error_flush_handler()


# Add a decorator to provide nice exception handling for validation errors for all commands. It avoids printing a confusing traceback, and also nicely formats validation errors.
Expand Down Expand Up @@ -153,15 +136,7 @@ def main(ctx: click.Context, targets: bool) -> None:
project = Project.parse(pp)
log.info(f"PreTeXt project found in `{utils.project_path()}`.")

# create file handler which logs even debug messages
logdir = pp / "logs"
logdir.mkdir(exist_ok=True)
logfile = logdir / f"{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}.log"
fh = logging.FileHandler(logfile, mode="w")
fh.setLevel(logging.DEBUG)
file_log_format = logging.Formatter("{levelname:<8}: {message}", style="{")
fh.setFormatter(file_log_format)
log.addHandler(fh)
logger.add_log_file_handler(pp / "logs")

# permanently change working directory for rest of process
os.chdir(pp)
Expand Down Expand Up @@ -565,7 +540,6 @@ def build(
)
targets = [target]
log.debug(f"Building standalone document with target {target.name}")
log.debug(target)
else:
targets = [project.get_target(name=target_name)]
except AssertionError as e:
Expand All @@ -592,7 +566,6 @@ def build(
for t in targets:
t.source = Path(source_file).resolve()
log.warning(f"Overriding source file for target with: {t.source}")
log.debug(t)

# Call generate if flag is set
if generate and not no_generate:
Expand Down
44 changes: 44 additions & 0 deletions pretext/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import datetime
from pathlib import Path
import sys
import logging
import click_log

log = logging.getLogger("ptxlogger")


def add_log_stream_handler() -> None:
# Set up logging:
# click_handler logs all messages to stdout as the CLI runs
click_handler = logging.StreamHandler(sys.stdout)
click_handler.setFormatter(click_log.ColorFormatter())
log.addHandler(click_handler)


def get_log_error_flush_handler() -> logging.handlers.MemoryHandler:
# error_flush_handler captures error/critical logs for flushing to stderr at the end of a CLI run
sh = logging.StreamHandler(sys.stderr)
sh.setFormatter(click_log.ColorFormatter())
sh.setLevel(logging.ERROR)
error_flush_handler = logging.handlers.MemoryHandler(
capacity=1024 * 100,
flushLevel=100,
target=sh,
flushOnClose=False,
)
error_flush_handler.setLevel(logging.ERROR)
log.addHandler(error_flush_handler)
return error_flush_handler


def add_log_file_handler(log_folder_path: Path) -> None:
# create file handler which logs even debug messages
log_folder_path.mkdir(exist_ok=True)
logfile = (
log_folder_path / f"{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}.log"
)
fh = logging.FileHandler(logfile, mode="w")
fh.setLevel(logging.DEBUG)
file_log_format = logging.Formatter("{levelname:<8}: {message}", style="{")
fh.setFormatter(file_log_format)
log.addHandler(fh)
5 changes: 5 additions & 0 deletions pretext/project/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
from .. import VERSION


# If we want to always spit out log messages to stdout even when this module is imported as a library, we could do so with the following two lines:
# from .. import logger
# log = logger.log

# Otherwise, we just set up the logger here to be used by the CLI.
log = logging.getLogger("ptxlogger")


Expand Down

0 comments on commit f4ed272

Please sign in to comment.