Is it the correct way to do it?
Yes, basically. at is the right tool and it should work even after you log out.
How can I capture any logs?
The POSIX specification of at states [emphasis mine]:
-m
Send mail to the invoking user after the at-job has run, announcing its completion. Standard output and standard error produced by the at-job shall be mailed to the user as well, unless redirected elsewhere. Mail shall be sent even if the job produces no output.
If -m is not used, the job's standard output and standard error shall be provided to the user by means of mail, unless they are redirected elsewhere; if there is no such output to provide, the implementation need not notify the user of the job's completion.
Either make sure you can receive mail, then check mail when the time comes; or redirect.
("When the time comes" means "after the job completes". Depending on what you are going to run, you may or may not be able to tell in advance how long it will take. Your at when invoked as at -l may (or may not) show you jobs currently running. Read man 1 at.)
at uses "a separate invocation of the shell". A command you pipe to at will be interpreted as shell code. This means you can specify redirections there. Example:
echo 'python3 my_script.py >>/path/to/log 2>&1' | at now + 2hours
Another example, this one logs timestamps before and after the actual command and uses a here document instead of echo:
at now + 2hours <<EOF
{
echo start
date
python3 my_script.py
echo "$?"
date
echo finish
} >/path/to/log 2>&1
EOF
Note if the redirection fails then an error message stating this fact will be mailed to you (and the shell code in { } won't be executed); so it's good to receive and check mail anyway.
if the script fails, at doesn't inform me
In general it's not "if the job fails". at will make no attempt to inform you by mail if you don't use -m and the job prints nothing to (not redirected) stdout and nothing to (not redirected) stderr. The job being silent is what matters, the exit status of the job is irrelevant.
Furthermore the exit status of the job is not reported (at least in my Debian).
In the example above I included echo "$?". This is how you can get the exit status of python3 my_script.py.
is it [i.e. at] really meant to do that?
Yes, that behavior is by design. You may call it not-the-best design if you want, but note each job is run in a separate process group with no controlling terminal, so it can work even after you log out; this is a huge advantage sometimes. Mail is a good way to reach user who may be logged out at the moment.
Still, because you give shell code to at, you can easily pass multiple commands and use redirections, thus fully customize what is printed where and not rely on mail (mail can still be useful in case of erroneous redirection(s)).
Should I use another tool?
It's up to you. In my opinion there is probably no need. at is a well established and standard tool. Maybe there are limitations of at that can be reasons to want a better tool, but the problem in question should not be seen as one of them, because it can easily be solved, as shown above.
Additionally in *nix there are general ways to customize commands. Examples:
alias at='at -m' will automatically add -m to at commands in your shell. This way you can force at to send mail unconditionally and you do it without typing -m each time.
This shell function:
atl () (
(printf "exec >'%s' 2>&1\n" "$LOG"; cat) | at "$@"
)
will allow you to do:
echo python3 my_script.py | LOG=/path/to/log atl now + 2hours
The above function is a proof of concept, it's potentially unsafe. If expanded $LOG contains single-quotes then it will misbehave. If the value of $LOG is not under your total control then undesired (or even rogue) code can be executed. To easily fix, use %q instead of '%s'; xor (in Bash) use %s instead of '%s' and "${LOG@Q}"instead of"$LOG"`. These methods are not portable though. Other shells may give you similar possibilities. A modified function that should work in Bash:
atl () {
(printf "exec >%s 2>&1\n" "${LOG@Q}"; cat) | at "$@"
}
With this knowledge please answer "should I use another tool?" for yourself.