-
Notifications
You must be signed in to change notification settings - Fork 151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add rich exception formatting, configurable from logging.yaml
#6640
Conversation
✅ Deploy Preview for meltano ready!
To edit notification comments on pull requests, go to your Netlify site settings. |
Codecov Report
@@ Coverage Diff @@
## main #6640 +/- ##
==========================================
- Coverage 82.99% 82.91% -0.08%
==========================================
Files 178 178
Lines 11365 11370 +5
Branches 1555 1555
==========================================
- Hits 9432 9428 -4
- Misses 1668 1676 +8
- Partials 265 266 +1
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
@pandemicsyn looking at this again, and after chatting a bit with AJ, I don't love that with self.settings_service.feature_flag(
FeatureFlags.EXCEPTION_FORMATTER, raise_error=False
) as exception_formatter:
output_logger = OutputLogger(log_file, format=exception_formatter) The main reason to prefer passing the project over arguments is if we expect to add lots of other feature flags in future for controlling the output format. I guess having the |
@kgpayne yea, definitely not keen of having to have the OutputLogger aware of projects. OutputLogger should stay as dumb as possible for as long as possible I think. Could we add the meltano/src/meltano/core/logging/formatters.py Lines 35 to 37 in 0c89bcd
If configuring it from setup_logging isn't easily doable (I can't remember if there are gotcha's there related to OutputLogger), then I'd be ok with adding |
Forgot how OutputLogger works and that it just injects its own handler. You'll probably still need to pass in a formatter, e.g.
🥷 edit: To clarify, probably need to enable rich exception formatting in both spots (in our default console renderer that we configure in setup_logging and in OutputLogger), since OutputLogger isn't always in the mix. |
c009d70
to
8321f2e
Compare
Ok, I think I have this working. As per @pandemicsyn suggestion above, this PR adds I also can't see an obvious way to feature-flag
@aaronsteers is |
logging.yaml
@pandemicsyn and @kgpayne re:
Would it work to let the feature flag dictate what is 'default' when no exception handler is provided? Here's what I was hoping for:
We likely will not get as many folks creating a new I think I would still prefer a feature flag approach to toggle the default (additionally, I mean) , if its not a huge amount of effort to do so, but I'm also okay with just enabling by default in this PR, and then the extra config file is needed to turn it off rather than turning it on. What do you think? |
@aaronsteers I think the feature flag could dictate what is
👍 that makes sense. Just want to draw awareness to the fact that - if this is expected to be a permanent flag, we should maybe consider it becoming a regular cli option at some point. This is just my personal philosophy, but IMHO, feature flags work best when they're not super long-lived (i.e. they exist just to help roll out a feature and get it ready for prime time).
Considering how often we catch flak for our existing colorized output - i definitely have mixed feelings about turning it on by default without at least seeing an example of it, but as long as:
I probably wouldn't object too much 😁 |
@edgarrmondragon / @pandemicsyn - Would we block on this codecov CI alarm?: https://github.com/meltano/meltano/pull/6640/checks?check_run_id=8139607011 @pandemicsyn - Regarding the default behavior and how the interplay between feature flag and log config should play out, I think we're close to path forward. Will try a zoom real quick to talk through. Otherwise will post back here with my thoughts shortly. |
@aaronsteers I think the function has simple enough inputs and output that it'd be quick to add a few tests that validate the resulting formatter has the right attributes. |
@pandemicsyn - does this look right to you too? cc @kgpayne - hopefully this unblocks you to finalize the PR. |
@aaronsteers (cc @pandemicsyn) if I understand the above correctly, you are asking for i) for rich to be enabled by default and ii) if its possible to have rich enabled but colors disabled? Based on this feedback from the previous round of discussion:
I made the following changes this afternoon:
This means:
From this:
It sounds like I need to walk back todays changes and the previous addition of a configurable |
@kgpayne re:
Yes - let's default this to
If it's easier to just remove the feature flag and/or the |
f266fed
to
82e6d02
Compare
Ok, I think I have this in good shape:
|
Setup by installing and creating sample project:
Without debug logging, no change to error report (this is expected):
With debug logging here's the before behavior: "Before" Behavioraj@ajs-macbook-pro deleteme-temp2 % meltano --log-level=debug schedule add invalid-cron-sched --interval=not-legit --job=asdf
2022-09-02T19:13:45.893787Z [info ] Environment 'dev' is active
2022-09-02T19:13:45.989954Z [debug ] Creating engine <meltano.core.project.Project object at 0x10e1980a0>@sqlite:////Users/aj/Source/deleteme-temp2/.meltano/meltano.db
2022-09-02T19:13:46.340154Z [debug ] not-legit
Traceback (most recent call last):
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/__init__.py", line 66, in _run_cli
cli(obj={"project": None})
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/click/core.py", line 1130, in __call__
return self.main(*args, **kwargs)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/cli.py", line 38, in main
return super().main(*args, windows_expand_args=False, **kwargs)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/utils.py", line 541, in invoke
super().invoke(ctx) # noqa: WPS608
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/utils.py", line 530, in invoke
super().invoke(ctx) # noqa: WPS608
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/utils.py", line 577, in invoke
super().invoke(ctx) # noqa: WPS608
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/schedule.py", line 131, in add
_add_job(ctx, name, job, interval)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/schedule.py", line 76, in _add_job
added_schedule = schedule_service.add(name, job, interval)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/core/schedule_service.py", line 135, in add
self.add_schedule(schedule)
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/core/schedule_service.py", line 199, in add_schedule
raise BadCronError(schedule.interval)
meltano.core.schedule_service.BadCronError: not-legit
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/aj/.local/pipx/venvs/meltano/lib/python3.8/site-packages/meltano/cli/__init__.py", line 74, in _run_cli
raise CliError(str(err)) from err
meltano.cli.utils.CliError: not-legit
not-legit With these updates, results are formatted nicely but the output is MUCH more verbose and harder to grok for this reason: New Outputaj@ajs-macbook-pro deleteme-temp2 % meltano6640 --log-level=debug schedule add invalid-cron-sched --interval=not-legit --job=asdf
2022-09-02T19:07:54.243398Z [info ] Environment 'dev' is active
2022-09-02T19:07:54.344180Z [debug ] Creating engine <meltano.core.project.Project object at 0x108fb6580>@sqlite:////Users/aj/Source/deleteme-temp2/.meltano/meltano.db
2022-09-02T19:07:54.996152Z [debug ] not-legit
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/__init__.py:66 │
│ in _run_cli │
│ │
│ 63 │ """Run the Meltano CLI.""" │
│ 64 │ try: │
│ 65 │ │ try: # noqa: WPS505 │
│ ❱ 66 │ │ │ cli(obj={"project": None}) │
│ 67 │ │ except ProjectReadonly as err: │
│ 68 │ │ │ raise CliError( │
│ 69 │ │ │ │ f"The requested action could not be completed: {err}" │
│ │
│ ╭───────────── locals ──────────────╮ │
│ │ cli_error = CliError('not-legit') │ │
│ ╰───────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/click/core.py:1130 in │
│ __call__ │
│ │
│ 1127 │ │
│ 1128 │ def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: │
│ 1129 │ │ """Alias for :meth:`main`.""" │
│ ❱ 1130 │ │ return self.main(*args, **kwargs) │
│ 1131 │
│ 1132 │
│ 1133 class Command(BaseCommand): │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ args = () │ │
│ │ kwargs = { │ │
│ │ │ 'obj': { │ │
│ │ │ │ 'project': <meltano.core.project.Project object at 0x108fb6580>, │ │
│ │ │ │ 'verbosity': 0, │ │
│ │ │ │ 'is_default_environment': True, │ │
│ │ │ │ 'tracker': <meltano.core.tracking.tracker.Tracker object at 0x108fc7dc0>, │ │
│ │ │ │ 'schedule_service': <meltano.core.schedule_service.ScheduleService object │ │
│ │ at 0x1090e2df0>, │ │
│ │ │ │ 'task_sets_service': <meltano.core.task_sets_service.TaskSetsService object │ │
│ │ at 0x109363fa0> │ │
│ │ │ } │ │
│ │ } │ │
│ │ self = <NoWindowsGlobbingGroup cli> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/cli.py:38 in │
│ main │
│ │
│ 35 │ │ │ args: Positional arguments for the Click group. │
│ 36 │ │ │ kwargs: Keyword arguments for the Click group. │
│ 37 │ │ """ │
│ ❱ 38 │ │ return super().main(*args, windows_expand_args=False, **kwargs) │
│ 39 │
│ 40 │
│ 41 @click.group( │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ __class__ = <class 'meltano.cli.cli.NoWindowsGlobbingGroup'> │ │
│ │ args = () │ │
│ │ kwargs = { │ │
│ │ │ 'obj': { │ │
│ │ │ │ 'project': <meltano.core.project.Project object at 0x108fb6580>, │ │
│ │ │ │ 'verbosity': 0, │ │
│ │ │ │ 'is_default_environment': True, │ │
│ │ │ │ 'tracker': <meltano.core.tracking.tracker.Tracker object at │ │
│ │ 0x108fc7dc0>, │ │
│ │ │ │ 'schedule_service': <meltano.core.schedule_service.ScheduleService │ │
│ │ object at 0x1090e2df0>, │ │
│ │ │ │ 'task_sets_service': <meltano.core.task_sets_service.TaskSetsService │ │
│ │ object at 0x109363fa0> │ │
│ │ │ } │ │
│ │ } │ │
│ │ self = <NoWindowsGlobbingGroup cli> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/click/core.py:1055 in main │
│ │
│ 1052 │ │ try: │
│ 1053 │ │ │ try: │
│ 1054 │ │ │ │ with self.make_context(prog_name, args, **extra) as ctx: │
│ ❱ 1055 │ │ │ │ │ rv = self.invoke(ctx) │
│ 1056 │ │ │ │ │ if not standalone_mode: │
│ 1057 │ │ │ │ │ │ return rv │
│ 1058 │ │ │ │ │ # it's not safe to `ctx.exit(rv)` here! │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ args = [ │ │
│ │ │ 'schedule', │ │
│ │ │ 'add', │ │
│ │ │ 'invalid-cron-sched', │ │
│ │ │ '--interval=not-legit', │ │
│ │ │ '--job=asdf' │ │
│ │ ] │ │
│ │ complete_var = None │ │
│ │ ctx = <click.core.Context object at 0x107bf4f70> │ │
│ │ extra = { │ │
│ │ │ 'obj': { │ │
│ │ │ │ 'project': <meltano.core.project.Project object at │ │
│ │ 0x108fb6580>, │ │
│ │ │ │ 'verbosity': 0, │ │
│ │ │ │ 'is_default_environment': True, │ │
│ │ │ │ 'tracker': <meltano.core.tracking.tracker.Tracker object at │ │
│ │ 0x108fc7dc0>, │ │
│ │ │ │ 'schedule_service': │ │
│ │ <meltano.core.schedule_service.ScheduleService object at 0x1090e2df0>, │ │
│ │ │ │ 'task_sets_service': │ │
│ │ <meltano.core.task_sets_service.TaskSetsService object at 0x109363fa0> │ │
│ │ │ } │ │
│ │ } │ │
│ │ prog_name = 'meltano6640' │ │
│ │ self = <NoWindowsGlobbingGroup cli> │ │
│ │ standalone_mode = True │ │
│ │ windows_expand_args = False │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/utils.py:541 in │
│ invoke │
│ │
│ 538 │ │ ctx.ensure_object(dict) │
│ 539 │ │ if ctx.obj.get("tracker"): │
│ 540 │ │ │ ctx.obj["tracker"].add_contexts(CliContext.from_click_context(ctx)) │
│ ❱ 541 │ │ super().invoke(ctx) # noqa: WPS608 │
│ 542 │
│ 543 │
│ 544 class InstrumentedCmd(click.Command): │
│ │
│ ╭───────────────────────── locals ──────────────────────────╮ │
│ │ __class__ = <class 'meltano.cli.utils.InstrumentedGroup'> │ │
│ │ ctx = <click.core.Context object at 0x107bf4f70> │ │
│ │ self = <NoWindowsGlobbingGroup cli> │ │
│ ╰───────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/click/core.py:1657 in invoke │
│ │
│ 1654 │ │ │ │ super().invoke(ctx) │
│ 1655 │ │ │ │ sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) │
│ 1656 │ │ │ │ with sub_ctx: │
│ ❱ 1657 │ │ │ │ │ return _process_result(sub_ctx.command.invoke(sub_ctx)) │
│ 1658 │ │ │
│ 1659 │ │ # In chain mode we create the contexts step by step, but after the │
│ 1660 │ │ # base command has been invoked. Because at that point we do not │
│ │
│ ╭───────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │ __class__ = <class 'click.core.MultiCommand'> │ │
│ │ _process_result = <function MultiCommand.invoke.<locals>._process_result at 0x105a63160> │ │
│ │ args = ['add', 'invalid-cron-sched', '--interval=not-legit', '--job=asdf'] │ │
│ │ cmd = <InstrumentedDefaultGroup schedule> │ │
│ │ cmd_name = 'schedule' │ │
│ │ ctx = <click.core.Context object at 0x107bf4f70> │ │
│ │ self = <NoWindowsGlobbingGroup cli> │ │
│ │ sub_ctx = <click.core.Context object at 0x105b22fd0> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/utils.py:530 in │
│ invoke │
│ │
│ 527 │ │ ctx.ensure_object(dict) │
│ 528 │ │ if ctx.obj.get("tracker"): │
│ 529 │ │ │ ctx.obj["tracker"].add_contexts(CliContext.from_click_context(ctx)) │
│ ❱ 530 │ │ super().invoke(ctx) # noqa: WPS608 │
│ 531 │
│ 532 │
│ 533 class InstrumentedGroup(click.Group): │
│ │
│ ╭───────────────────────────── locals ─────────────────────────────╮ │
│ │ __class__ = <class 'meltano.cli.utils.InstrumentedDefaultGroup'> │ │
│ │ ctx = <click.core.Context object at 0x105b22fd0> │ │
│ │ self = <InstrumentedDefaultGroup schedule> │ │
│ ╰──────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/click/core.py:1657 in invoke │
│ │
│ 1654 │ │ │ │ super().invoke(ctx) │
│ 1655 │ │ │ │ sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) │
│ 1656 │ │ │ │ with sub_ctx: │
│ ❱ 1657 │ │ │ │ │ return _process_result(sub_ctx.command.invoke(sub_ctx)) │
│ 1658 │ │ │
│ 1659 │ │ # In chain mode we create the contexts step by step, but after the │
│ 1660 │ │ # base command has been invoked. Because at that point we do not │
│ │
│ ╭───────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │ __class__ = <class 'click.core.MultiCommand'> │ │
│ │ _process_result = <function MultiCommand.invoke.<locals>._process_result at 0x108fdd280> │ │
│ │ args = [] │ │
│ │ cmd = <PartialInstrumentedCmd add> │ │
│ │ cmd_name = 'add' │ │
│ │ ctx = <click.core.Context object at 0x105b22fd0> │ │
│ │ self = <InstrumentedDefaultGroup schedule> │ │
│ │ sub_ctx = <click.core.Context object at 0x1090e2dc0> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/utils.py:577 in │
│ invoke │
│ │
│ 574 │ │ if ctx.obj.get("tracker"): │
│ 575 │ │ │ ctx.obj["tracker"].add_contexts(CliContext.from_click_context(ctx)) │
│ 576 │ │ │ ctx.obj["tracker"].track_command_event(CliEvent.started) │
│ ❱ 577 │ │ super().invoke(ctx) # noqa: WPS608 │
│ 578 │
│ │
│ ╭──────────────────────────── locals ────────────────────────────╮ │
│ │ __class__ = <class 'meltano.cli.utils.PartialInstrumentedCmd'> │ │
│ │ ctx = <click.core.Context object at 0x1090e2dc0> │ │
│ │ self = <PartialInstrumentedCmd add> │ │
│ ╰────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/click/core.py:1404 in invoke │
│ │
│ 1401 │ │ │ echo(style(message, fg="red"), err=True) │
│ 1402 │ │ │
│ 1403 │ │ if self.callback is not None: │
│ ❱ 1404 │ │ │ return ctx.invoke(self.callback, **ctx.params) │
│ 1405 │ │
│ 1406 │ def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"] │
│ 1407 │ │ """Return a list of completions for the incomplete value. Looks │
│ │
│ ╭───────────────────── locals ──────────────────────╮ │
│ │ ctx = <click.core.Context object at 0x1090e2dc0> │ │
│ │ self = <PartialInstrumentedCmd add> │ │
│ ╰───────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/click/core.py:760 in invoke │
│ │
│ 757 │ │ │
│ 758 │ │ with augment_usage_errors(__self): │
│ 759 │ │ │ with ctx: │
│ ❱ 760 │ │ │ │ return __callback(*args, **kwargs) │
│ 761 │ │
│ 762 │ def forward( │
│ 763 │ │ __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # noqa: B902 │
│ │
│ ╭──────────────────────────── locals ─────────────────────────────╮ │
│ │ _Context__callback = <function add at 0x108f16040> │ │
│ │ _Context__self = <click.core.Context object at 0x1090e2dc0> │ │
│ │ args = () │ │
│ │ ctx = <click.core.Context object at 0x1090e2dc0> │ │
│ │ kwargs = { │ │
│ │ │ 'interval': 'not-legit', │ │
│ │ │ 'job': 'asdf', │ │
│ │ │ 'name': 'invalid-cron-sched', │ │
│ │ │ 'extractor': None, │ │
│ │ │ 'loader': None, │ │
│ │ │ 'transform': 'skip', │ │
│ │ │ 'start_date': None │ │
│ │ } │ │
│ ╰─────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/click/decorators.py:26 in │
│ new_func │
│ │
│ 23 │ """ │
│ 24 │ │
│ 25 │ def new_func(*args, **kwargs): # type: ignore │
│ ❱ 26 │ │ return f(get_current_context(), *args, **kwargs) │
│ 27 │ │
│ 28 │ return update_wrapper(t.cast(F, new_func), f) │
│ 29 │
│ │
│ ╭────────────────── locals ──────────────────╮ │
│ │ args = () │ │
│ │ f = <function add at 0x108f12f70> │ │
│ │ kwargs = { │ │
│ │ │ 'interval': 'not-legit', │ │
│ │ │ 'job': 'asdf', │ │
│ │ │ 'name': 'invalid-cron-sched', │ │
│ │ │ 'extractor': None, │ │
│ │ │ 'loader': None, │ │
│ │ │ 'transform': 'skip', │ │
│ │ │ 'start_date': None │ │
│ │ } │ │
│ ╰────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/schedule.py:131 │
│ in add │
│ │
│ 128 │ │ │
│ 129 │ │ _add_elt(ctx, name, extractor, loader, transform, interval, start_date) │
│ 130 │ │ return │
│ ❱ 131 │ _add_job(ctx, name, job, interval) │
│ 132 │
│ 133 │
│ 134 def _format_job_list_output(entry: Schedule, job: TaskSets) -> dict: │
│ │
│ ╭──────────────────────── locals ─────────────────────────╮ │
│ │ ctx = <click.core.Context object at 0x1090e2dc0> │ │
│ │ extractor = None │ │
│ │ interval = 'not-legit' │ │
│ │ job = 'asdf' │ │
│ │ loader = None │ │
│ │ name = 'invalid-cron-sched' │ │
│ │ start_date = None │ │
│ │ transform = 'skip' │ │
│ ╰─────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/schedule.py:76 │
│ in _add_job │
│ │
│ 73 │ _, session_maker = project_engine(project) │
│ 74 │ session = session_maker() │
│ 75 │ try: │
│ ❱ 76 │ │ added_schedule = schedule_service.add(name, job, interval) │
│ 77 │ │ click.echo( │
│ 78 │ │ │ f"Scheduled job '{added_schedule.name}' at {added_schedule.interval}" │
│ 79 │ │ ) │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ _ = Engine(sqlite:////Users/aj/Source/deleteme-temp2/.meltano/meltano.db) │ │
│ │ ctx = <click.core.Context object at 0x1090e2dc0> │ │
│ │ interval = 'not-legit' │ │
│ │ job = 'asdf' │ │
│ │ name = 'invalid-cron-sched' │ │
│ │ project = <meltano.core.project.Project object at 0x108fb6580> │ │
│ │ schedule_service = <meltano.core.schedule_service.ScheduleService object at 0x1090e2df0> │ │
│ │ session = <sqlalchemy.orm.session.Session object at 0x1093692b0> │ │
│ │ session_maker = sessionmaker(class_='Session', │ │
│ │ bind=Engine(sqlite:////Users/aj/Source/deleteme-temp2/.meltano/meltano.d… │ │
│ │ autoflush=True, autocommit=False, expire_on_commit=True) │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/core/schedule_servic │
│ e.py:135 in add │
│ │
│ 132 │ │ │ The added schedule. │
│ 133 │ │ """ │
│ 134 │ │ schedule = Schedule(name=name, job=job, interval=interval, env=env) │
│ ❱ 135 │ │ self.add_schedule(schedule) │
│ 136 │ │ return schedule │
│ 137 │ │
│ 138 │ def remove(self, name) -> str: │
│ │
│ ╭───────────────────────────────────── locals ─────────────────────────────────────╮ │
│ │ env = {} │ │
│ │ interval = 'not-legit' │ │
│ │ job = 'asdf' │ │
│ │ name = 'invalid-cron-sched' │ │
│ │ schedule = <meltano.core.schedule.Schedule object at 0x109363610> │ │
│ │ self = <meltano.core.schedule_service.ScheduleService object at 0x1090e2df0> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/core/schedule_servic │
│ e.py:199 in add_schedule │
│ │
│ 196 │ │ │ and schedule.interval != "@once" │
│ 197 │ │ │ and not croniter.is_valid(schedule.interval) │
│ 198 │ │ ): │
│ ❱ 199 │ │ │ raise BadCronError(schedule.interval) │
│ 200 │ │ │
│ 201 │ │ with self.project.meltano_update() as meltano: │
│ 202 │ │ │ # guard if it already exists │
│ │
│ ╭───────────────────────────────────── locals ─────────────────────────────────────╮ │
│ │ schedule = <meltano.core.schedule.Schedule object at 0x109363610> │ │
│ │ self = <meltano.core.schedule_service.ScheduleService object at 0x1090e2df0> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
BadCronError: not-legit
The above exception was the direct cause of the following exception:
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/aj/.local/pipx/venvs/meltano6640/lib/python3.8/site-packages/meltano/cli/__init__.py:74 │
│ in _run_cli │
│ │
│ 71 │ │ except KeyboardInterrupt: # noqa: WPS329 │
│ 72 │ │ │ raise │
│ 73 │ │ except Exception as err: │
│ ❱ 74 │ │ │ raise CliError(str(err)) from err │
│ 75 │ except CliError as cli_error: │
│ 76 │ │ cli_error.print() │
│ 77 │ │ sys.exit(1) │
│ │
│ ╭───────────── locals ──────────────╮ │
│ │ cli_error = CliError('not-legit') │ │
│ ╰───────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
CliError: not-legit
not-legit |
@kgpayne - Have you done any usage tests on your side? Based on the output in my comment above, we may need to remove some frames as documented here: https://rich.readthedocs.io/en/stable/traceback.html#suppressing-frames Probably not by coincidence, those docs give the example of removing stracktrace detail from 🥷 Edit: On reviewing the above logs, I think it makes sense to suppress frames from |
@kgpayne - Exciting to see this merged! Thanks for your quick work on adding the |
Closes #2971