Slide 1

Slide 1 text

Everything is broken, and I don’t know why. Python edition PyOhio July 30th 2017 Matt Robenolt

Slide 2

Slide 2 text

hello @mattrobenolt

Slide 3

Slide 3 text

Core contributor

Slide 4

Slide 4 text

If an exception happens in production, and nobody sees the logs, did it really happen? — Taylor Swift “ ”

Slide 5

Slide 5 text

Damn Stebe, it works for me. gtfo my inbox. “ ” — Josh

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

But first, some broken software.

Slide 8

Slide 8 text

Errors in: Computers EAX CPU registers EBX ECX

Slide 9

Slide 9 text

Errors in: Computers EAX CPU registers EBX SYS_open ECX

Slide 10

Slide 10 text

Errors in: Computers EAX CPU registers EBX SYS_open ECX "foo.txt"

Slide 11

Slide 11 text

Errors in: Computers EAX CPU registers EBX SYS_open ECX "foo.txt" O_RDONLY

Slide 12

Slide 12 text

Errors in: Computers EAX CPU registers EBX ECX "foo.txt" interrupt SYS_open O_RDONLY

Slide 13

Slide 13 text

Errors in: Computers EAX CPU registers EBX ECX "foo.txt" interrupt EAX -1 SYS_open O_RDONLY

Slide 14

Slide 14 text

#include int main () { FILE *fp; char buf[100]; fp = fopen("foo.txt", "r"); fgets(buf, 100, fp); fclose(fp); } Errors in: C

Slide 15

Slide 15 text

#include int main () { FILE *fp; char buf[100]; fp = fopen("foo.txt", "r"); fgets(buf, 100, fp); fclose(fp); } Errors in: C [1] 53482 segmentation fault ./a.out

Slide 16

Slide 16 text

#include int main () { FILE *fp; char buf[100]; fp = fopen("foo.txt", “r"); if (fp != NULL) { fgets(buf, 100, fp); fclose(fp); } } Errors in: C

Slide 17

Slide 17 text

package main import "os" func main() { buf := make([]byte, 100) fp, _ := os.Open("foo.txt") fp.Read(buf) fp.Close() } Errors in: Go

Slide 18

Slide 18 text

package main import "os" func main() { buf := make([]byte, 100) fp, _ := os.Open("foo.txt") fp.Read(buf) fp.Close() } Errors in: Go jk nothing happens

Slide 19

Slide 19 text

package main import "os" func main() { buf := make([]byte, 100) fp, err := os.Open(“foo.txt") if err != nil { return } fp.Read(buf) fp.Close() } Errors in: Go

Slide 20

Slide 20 text

use std::fs::File; use std::io::Read; fn main() { let mut fp = File::open("foo.txt").unwrap(); let mut buf = [0; 100]; fp.read_exact(&mut buf); drop(fp); } Errors in: Rust

Slide 21

Slide 21 text

use std::fs::File; use std::io::Read; fn main() { let mut fp = File::open("foo.txt").unwrap(); let mut buf = [0; 100]; fp.read_exact(&mut buf); drop(fp); } Errors in: Rust thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }', ../src/ libcore/result.rs:788 note: Run with `RUST_BACKTRACE=1` for a backtrace.

Slide 22

Slide 22 text

use std::fs::File; use std::io::Read; fn main() { match File::open("foo.txt") { Ok(mut fp) => { let mut buf = [0; 100]; fp.read_exact(&mut buf); drop(fp); }, Err(_) => { // }, } } Errors in: Rust

Slide 23

Slide 23 text

fp = open('foo.txt', 'r') buf = fp.read(100) fp.close() Errors in: Python

Slide 24

Slide 24 text

fp = open('foo.txt', 'r') buf = fp.read(100) fp.close() Errors in: Python Traceback (most recent call last): File "main.py", line 1, in fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt'

Slide 25

Slide 25 text

try: fp = open('foo.txt', 'r') except IOError: pass else: buf = fp.read(100) fp.close() Errors in: Python

Slide 26

Slide 26 text

try: fp = open('foo.txt', 'r') except IOError: pass else: buf = fp.read(100) fp.close() Errors in: Python Exceptions

Slide 27

Slide 27 text

Exceptions Errors vs

Slide 28

Slide 28 text

Errors

Slide 29

Slide 29 text

Errors Non-fatal, multiple may exist within a call stack at the same time, generally returned as a value.

Slide 30

Slide 30 text

Exceptions Fatal, must be handled, only one exists within a call stack, raised to abort current execution.

Slide 31

Slide 31 text

Exceptions Fatal, must be handled, only one exists within a call stack, raised to abort current execution.

Slide 32

Slide 32 text

Traceback (most recent call last): File "main.py", line 1, in fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt'

Slide 33

Slide 33 text

Traceback (most recent call last): File "main.py", line 1, in fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt' So what do we do with this thing?

Slide 34

Slide 34 text

Traceback (most recent call last): File "main.py", line 1, in fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt' So what do we do with this thing? …and where does it come from?

Slide 35

Slide 35 text

fp = open('foo.txt', 'r') buf = fp.read(100) fp.close()

Slide 36

Slide 36 text

import sys def excepthook(type, value, tb): print(type, value, tb) sys.excepthook = excepthook fp = open('foo.txt', 'r') buf = fp.read(100) fp.close()

Slide 37

Slide 37 text

import sys def excepthook(type, value, tb): print(type, value, tb) sys.excepthook = excepthook fp = open('foo.txt', 'r') buf = fp.read(100) fp.close() (, IOError(2, 'No such file or directory'), )

Slide 38

Slide 38 text

import sys def excepthook(type, value, tb): import traceback traceback.print_exception(type, value, tb) sys.excepthook = excepthook fp = open('foo.txt', 'r') buf = fp.read(100) fp.close()

Slide 39

Slide 39 text

import sys def excepthook(type, value, tb): import traceback traceback.print_exception(type, value, tb) sys.excepthook = excepthook fp = open('foo.txt', 'r') buf = fp.read(100) fp.close() Traceback (most recent call last): File "main.py", line 9, in fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt'

Slide 40

Slide 40 text

fp = open('foo.txt', 'r') buf = fp.read(100) fp.close()

Slide 41

Slide 41 text

try: fp = open('foo.txt', 'r') except IOError: import sys print(sys.exc_info()) else: buf = fp.read(100) fp.close()

Slide 42

Slide 42 text

try: fp = open('foo.txt', 'r') except IOError: import sys print(sys.exc_info()) else: buf = fp.read(100) fp.close() (, IOError(2, 'No such file or directory'), )

Slide 43

Slide 43 text

try: fp = open('foo.txt', 'r') except IOError: import sys, traceback traceback.print_exception(*sys.exc_info()) else: buf = fp.read(100) fp.close()

Slide 44

Slide 44 text

try: fp = open('foo.txt', ‘r') except IOError: import traceback traceback.print_exc() else: buf = fp.read(100) fp.close() Traceback (most recent call last): File "main.py", line 2, in fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt'

Slide 45

Slide 45 text

import sys print(sys.exc_info())

Slide 46

Slide 46 text

import sys print(sys.exc_info()) (None, None, None)

Slide 47

Slide 47 text

import sys try: raise Exception() except Exception: pass print(sys.exc_info())

Slide 48

Slide 48 text

import sys try: raise Exception() except Exception: pass print(sys.exc_info()) (None, None, None)

Slide 49

Slide 49 text

try: raise Exception() except Exception: import sys print(sys.exc_info())

Slide 50

Slide 50 text

try: raise Exception() except Exception: import sys print(sys.exc_info()) (, Exception(), )

Slide 51

Slide 51 text

try: raise Exception() except Exception: import traceback, sys traceback.print_exc(file=sys.stderr)

Slide 52

Slide 52 text

$ python main.py 2> errors.log

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

$ cat errors.log

Slide 55

Slide 55 text

$ cat errors.log raise Exception() Exception Traceback (most recent call last): File "main.py", line 3, in raise Exception() Exception Traceback (most recent call last): File "main.py", line 3, in raise Exception() Exception Traceback (most recent call last): File "main.py", line 3, in raise Exception() Exception Traceback (most recent call last): File "main.py", line 3, in

Slide 56

Slide 56 text

$ cat errors.log Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing1' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing2' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing3' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing4'

Slide 57

Slide 57 text

$ cat errors.log Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing1' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing2' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing3' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing4'

Slide 58

Slide 58 text

Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing1' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing2' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing3' Traceback (most recent call last): File "main.py", line 4, in my_thing = things[key] KeyError: 'thing4'

Slide 59

Slide 59 text

Damn Stebe, that variable should be right. You must have messed it up. “ ” — Darrell

Slide 60

Slide 60 text

things = {} key = sys.argv[1] try: my_thing = things[key] except KeyError: import traceback traceback.print_exc() print(globals(), locals())

Slide 61

Slide 61 text

things = {} key = sys.argv[1] try: my_thing = things[key] except KeyError: import traceback traceback.print_exc() print(globals(), locals())

Slide 62

Slide 62 text

things = {} key = sys.argv[1] try: my_thing = things[key] except KeyError: import traceback traceback.print_exc() print(globals(), locals()) Traceback (most recent call last): File "main.py", line 5, in things[key] KeyError: 'thing' ({'things': {},'key': 'thing'}, {'things': {}, 'key': 'thing'})

Slide 63

Slide 63 text

things = {} key = sys.argv[1] try: my_thing = things[key] except KeyError: import traceback traceback.print_exc() print(globals(), locals()) Traceback (most recent call last): File "main.py", line 5, in things[key] KeyError: 'thing' ({'things': {},'key': 'thing'}, {'things': {}, 'key': 'thing'})

Slide 64

Slide 64 text

things = {} key = sys.argv[1] try: my_thing = things[key] except KeyError: import traceback, json, sys json.dump({ 'exc': traceback.format_exc(), 'globals': globals(), 'locals': locals(), }, sys.stderr) Don’t actually do this, use: https://github.com/hynek/structlog

Slide 65

Slide 65 text

things = [0, 1, 2] def get_random_thing(n): return get_thing(randint(0, n)) def get_thing(index): try: return things[index] except IndexError: print(locals()) get_random_thing(10)

Slide 66

Slide 66 text

things = [0, 1, 2] def get_random_thing(n): return get_thing(randint(0, n)) def get_thing(index): try: return things[index] except IndexError: print(locals()) get_random_thing(10) {'index': 8}

Slide 67

Slide 67 text

def debug(): import sys tb = sys.exc_info()[2] idx = 0 while tb: idx += 1 frame = tb.tb_frame code = frame.f_code print({ 'line': tb.tb_lineno, 'locals': frame.f_locals, 'function': code.co_name, }) tb = tb.tb_next try: get_random_thing(10) except Exception: debug()

Slide 68

Slide 68 text

def debug(): import sys tb = sys.exc_info()[2] idx = 0 while tb: idx += 1 frame = tb.tb_frame code = frame.f_code print({ 'line': tb.tb_lineno, 'locals': frame.f_locals, 'function': code.co_name, }) tb = tb.tb_next try: get_random_thing(10) except Exception: debug() {'function': ‘', 'line': 31, 'locals': {'things': [0, 1, 2]}} {'function': 'get_random_thing', 'line': 7, 'locals': {'n': 4}} {'function': 'get_thing', 'line': 11, 'locals': {'index': 4}}

Slide 69

Slide 69 text

def debug(): report = { 'context': { 'argv': sys.argv, 'environ': os.environ, 'uname': os.uname(), 'time': time.time(), }, 'frames': [], }

Slide 70

Slide 70 text

_, e, tb = sys.exc_info() idx = 0 while tb: idx += 1 frame = tb.tb_frame code = frame.f_code report['frames'].append({ 'line': tb.tb_lineno, 'locals': frame.f_locals, 'function': code.co_name, 'filename': code.co_filename, 'context': linecache.getline( code.co_filename, tb.tb_lineno, ), }) tb = tb.tb_next

Slide 71

Slide 71 text

sendmail('[email protected]', e.message, serialize(report))

Slide 72

Slide 72 text

Hot damn Stebe, thanks for the information. Lemme fix that bug for you right away. “ ”

Slide 73

Slide 73 text

Sentry. We do all this shit for you.

Slide 74

Slide 74 text

Questions? I may or may not have answers. @mattrobenolt github.com/mattrobenolt sentry.io github.com/getsentry/sentry