Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Everything is broken, and I don't know why. Python edition.

Everything is broken, and I don't know why. Python edition.

PyOhio
July 30th 2017

Ce86d68173d477a17396b5e611468f52?s=128

Matt Robenolt

July 30, 2017
Tweet

More Decks by Matt Robenolt

Other Decks in Technology

Transcript

  1. Everything is broken, and I don’t know why. Python edition

    PyOhio July 30th 2017 Matt Robenolt
  2. hello @mattrobenolt

  3. Core contributor

  4. If an exception happens in production, and nobody sees the

    logs, did it really happen? — Taylor Swift “ ”
  5. Damn Stebe, it works for me. gtfo my inbox. “

    ” — Josh
  6. None
  7. But first, some broken software.

  8. Errors in: Computers EAX CPU registers EBX ECX

  9. Errors in: Computers EAX CPU registers EBX SYS_open ECX

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

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

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

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

    EAX -1 SYS_open O_RDONLY
  14. #include <stdio.h> int main () { FILE *fp; char buf[100];

    fp = fopen("foo.txt", "r"); fgets(buf, 100, fp); fclose(fp); } Errors in: C
  15. #include <stdio.h> 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
  16. #include <stdio.h> int main () { FILE *fp; char buf[100];

    fp = fopen("foo.txt", “r"); if (fp != NULL) { fgets(buf, 100, fp); fclose(fp); } } Errors in: C
  17. package main import "os" func main() { buf := make([]byte,

    100) fp, _ := os.Open("foo.txt") fp.Read(buf) fp.Close() } Errors in: Go
  18. 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
  19. 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
  20. 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
  21. 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.
  22. 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
  23. fp = open('foo.txt', 'r') buf = fp.read(100) fp.close() Errors in:

    Python
  24. 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 <module> fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt'
  25. try: fp = open('foo.txt', 'r') except IOError: pass else: buf

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

    = fp.read(100) fp.close() Errors in: Python Exceptions
  27. Exceptions Errors vs

  28. Errors

  29. Errors Non-fatal, multiple may exist within a call stack at

    the same time, generally returned as a value.
  30. Exceptions Fatal, must be handled, only one exists within a

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

    call stack, raised to abort current execution.
  32. Traceback (most recent call last): File "main.py", line 1, in

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

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

    <module> 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?
  35. fp = open('foo.txt', 'r') buf = fp.read(100) fp.close()

  36. 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()
  37. 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() (<type 'exceptions.IOError'>, IOError(2, 'No such file or directory'), <traceback object at 0x106810ea8>)
  38. 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()
  39. 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 <module> fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt'
  40. fp = open('foo.txt', 'r') buf = fp.read(100) fp.close()

  41. try: fp = open('foo.txt', 'r') except IOError: import sys print(sys.exc_info())

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

    else: buf = fp.read(100) fp.close() (<type 'exceptions.IOError'>, IOError(2, 'No such file or directory'), <traceback object at 0x106810ea8>)
  43. try: fp = open('foo.txt', 'r') except IOError: import sys, traceback

    traceback.print_exception(*sys.exc_info()) else: buf = fp.read(100) fp.close()
  44. 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 <module> fp = open('foo.txt', 'r') IOError: [Errno 2] No such file or directory: 'foo.txt'
  45. import sys print(sys.exc_info())

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

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

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

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

  50. try: raise Exception() except Exception: import sys print(sys.exc_info()) (<type 'exceptions.Exception'>,

    Exception(), <traceback object at 0x10ffbec20>)
  51. try: raise Exception() except Exception: import traceback, sys traceback.print_exc(file=sys.stderr)

  52. $ python main.py 2> errors.log

  53. None
  54. $ cat errors.log

  55. $ cat errors.log raise Exception() Exception Traceback (most recent call

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

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

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

    <module> my_thing = things[key] KeyError: 'thing1' Traceback (most recent call last): File "main.py", line 4, in <module> my_thing = things[key] KeyError: 'thing2' Traceback (most recent call last): File "main.py", line 4, in <module> my_thing = things[key] KeyError: 'thing3' Traceback (most recent call last): File "main.py", line 4, in <module> my_thing = things[key] KeyError: 'thing4'
  59. Damn Stebe, that variable should be right. You must have

    messed it up. “ ” — Darrell
  60. things = {} key = sys.argv[1] try: my_thing = things[key]

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

    except KeyError: import traceback traceback.print_exc() print(globals(), locals())
  62. 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 <module> things[key] KeyError: 'thing' ({'things': {},'key': 'thing'}, {'things': {}, 'key': 'thing'})
  63. 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 <module> things[key] KeyError: 'thing' ({'things': {},'key': 'thing'}, {'things': {}, 'key': 'thing'})
  64. 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
  65. 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)
  66. 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}
  67. 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()
  68. 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': ‘<module>', 'line': 31, 'locals': {'things': [0, 1, 2]}} {'function': 'get_random_thing', 'line': 7, 'locals': {'n': 4}} {'function': 'get_thing', 'line': 11, 'locals': {'index': 4}}
  69. def debug(): report = { 'context': { 'argv': sys.argv, 'environ':

    os.environ, 'uname': os.uname(), 'time': time.time(), }, 'frames': [], }
  70. _, 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
  71. sendmail('m@robenolt.com', e.message, serialize(report))

  72. Hot damn Stebe, thanks for the information. Lemme fix that

    bug for you right away. “ ”
  73. Sentry. We do all this shit for you.

  74. Questions? I may or may not have answers. @mattrobenolt github.com/mattrobenolt

    sentry.io github.com/getsentry/sentry