Skip to content
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: /usr/bin/script wrapper to send full tty output to sentry #124

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 51 additions & 4 deletions devenv/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import argparse
import os
import subprocess
import sys
from collections.abc import Sequence

from devenv import bootstrap
Expand Down Expand Up @@ -75,17 +77,62 @@ def devenv(argv: Sequence[str], config_path: str) -> ExitCode:


def main() -> ExitCode:
import sys
# this is also used to see if we're the child process
script_logfile = os.environ.get("SCRIPT")

if script_logfile:
return devenv(sys.argv, f"{home}/.config/sentry-devenv/config.ini")

import tempfile

_, fp = tempfile.mkstemp()
# script (macos/linux) runs the subcommand with a tty, and tees the output to a file.
# this way we can very easily capture all output from devenv and send it
# to sentry as an attachment if an error occurs.
cmd = ("/usr/bin/script", "-qe", fp, *sys.argv)

# the reason we're subprocessing instead of os.execv(cmd[0], cmd)
# is that script must exit (so that the complete log file is committed to disk)
# before sentry sends the event...
rc = subprocess.call(cmd)

if rc == 0:
return rc

# i'd love to be able to send a full event in the child then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can do something something trace id and have both exist? and just link them after the fact?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahhh that might work, i'm thinking we start a transaction in the parent and start a span for the child process then only transaction.finish() if an error happens in the child

not sure what the transaction would look like in sentry ui (like, can we easily see the child error event) but gonna give it a go

# upload the attachment to that event id in the parent, but unfortunately there's
# no easy way to add an attachment to an existing event,
# so we have to give up getting a python stacktrace,
# and can only use sentry-sdk to send an attachment.
import sentry_sdk
from sentry_sdk.scope import Scope
import getpass

sentry_sdk.init(
# https://sentry.sentry.io/settings/projects/sentry-dev-env/keys/
dsn="https://[email protected]/5723503",
# enable performance monitoring
enable_tracing=True,
# disable performance monitoring
enable_tracing=False,
)

return devenv(sys.argv, f"{home}/.config/sentry-devenv/config.ini")
scope = Scope.get_current_scope()

# would really like to be able to set filename to the python exception title
# because seeing KeyboardInterrupt vs CalledProcessError is more helpful than
# "tmp29387ldf", but see above comment
scope.add_attachment(path=fp)

client = Scope.get_client()

user = getpass.getuser()
computer = client.options.get("server_name", "unknown")

# events are grouped under user@computer
scope.fingerprint = [f"{user}@{computer}"]

sentry_sdk.capture_message(f"{user}@{computer}")

return rc


if __name__ == "__main__":
Expand Down
Loading