SlideShare a Scribd company logo
How I Built a Power Debugger
Out of the Standard Library and
Things I Found on the Internet
Doug Hellmann
PyCon US 2016
I Built a Power Debugger!
Doug Hellmann
PyCon US 2016
How
I Built a Power Debugger!
Doug Hellmann
PyCon US 2016
github.com/dhellmann/smiley
smiley.readthedocs.org
Features
• Record calls with data
• Remote monitoring, local
analysis
• Browse history
• Learn new tools
flickr/Kangrex
class Publisher(object):
def __init__(self, endpoint,
high_water_mark=10000):
self.context = zmq.Context()
self.pub_socket = 
self.context.socket(zmq.PUSH)
self.pub_socket.bind(endpoint)
self.pub_socket.identity = 'publisher'
self.pub_socket.hwm = high_water_mark
def send(self, msg_type, data):
msg = [
msg_type,
json.dumps(data,
default=self._json_special_types),
]
self.pub_socket.send_multipart(msg)
def trace_calls(self, frame, event, arg):
co = frame.f_code
filename = co.co_filename
if filename in (__file__,):
# Ignore ourself
return
self._send_notice(frame, event, arg)
return self.trace_calls
def _send_notice(self, frame, event, arg):
co = frame.f_code
func_name = co.co_name
line_no = frame.f_lineno
filename = os.path.abspath(co.co_filename)
for d in IGNORE_DIRS:
if filename.startswith(d):
return
# …
# …
interesting_locals = {
n: v
for n, v in frame.f_locals.items()
if (not inspect.ismodule(v)
and not inspect.isfunction(v)
and not inspect.ismethod(v)
and (n[:2] != '__' and n[-2:] != '__'))
}
# …
# …
self.publisher.send(
event,
{'func_name': func_name,
'line_no': line_no,
'filename': filename,
'arg': arg,
'locals': interesting_locals,
'timestamp': time.time(),
'run_id': self.run_id,
})
$ smiley help
usage: smiley [--version] [-v] [--log-file LOG_FILE]
[-q] [-h] [--debug]
smiley spies on your apps as they run
optional arguments:
--version show program's version number
and exit
-v, --verbose Increase verbosity of output.
--log-file LOG_FILE Specify a file to log output.
-q, --quiet suppress output except warnings
-h, --help show this help message and exit
--debug show tracebacks on errors
Commands:
complete print bash completion command
help print detailed help for another command
monitor Listen for running programs and show
their progress.
run Run another program with monitoring
enabled.
$ smiley help run
usage: smiley run [-h] [--socket SOCKET] command
[command ...]
Run another program with monitoring enabled.
positional arguments:
command the command to spy on
optional arguments:
-h, --help show this help message and exit
--socket SOCKET URL for the socket where the listener
will be (tcp://127.0.0.1:5556)
$ smiley help monitor
usage: smiley monitor [-h] [--socket SOCKET]
Listen for running programs and show their progress.
optional arguments:
-h, --help show this help message and exit
--socket SOCKET URL for the socket where to monitor on
(tcp://127.0.0.1:5556)
def _process_message(self, msg):
print 'MESSAGE:', msg
msg_type, msg_payload = msg
if msg_type == 'start_run':
print (‘Starting new run:',
msg_payload.get(‘command_line'))
elif msg_type == 'end_run':
print 'Finished run'
else:
line = linecache.getline(msg_payload['filename'],
msg_payload['line_no']).rstrip()
if msg_type == 'return':
print '%s:%4s: return>>> %s' % (
msg_payload['filename'],
msg_payload[‘line_no'], msg_payload['arg'])
else:
print '%s:%4s: %s' % (
msg_payload['filename'],
msg_payload[‘line_no'], line)
if msg_payload.get('locals'):
for n, v in sorted(msg_payload['locals'].items()):
print '%s %s = %s' % (
' ' * len(msg_payload['filename']),
n,
v,
)
print
def gen(m):
for i in xrange(m):
yield i
def c(input):
print 'input =', input
data = list(gen(input))
print 'Leaving c()'
def b(arg):
val = arg * 5
c(val)
print 'Leaving b()'
return val
def a():
print 'args:', sys.argv
b(2)
print 'Leaving a()'
a()
$ smiley monitor
Waiting for incoming data
MESSAGE: ['start_run', {u'command_line': [u'simple.py'], u'run_id':
u'e87302b2-402a-4243-bb27-69a467d4bd8e'}]
Starting new run: [u'simple.py']
MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.142863,
u'line_no': 1,
u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py',
u'func_name': u'<module>', u'arg': None, u'locals': {u'self':
u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line':
[u'simple.py']}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys
command_line =
[u'simple.py']
self =
<smiley.tracer.Tracer object at 0x103caff10>
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.143175,
u'line_no': 1,
u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py',
u'func_name': u'<module>', u'arg': None, u'locals': {u'self':
u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line':
[u'simple.py']}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys
command_line =
[u'simple.py']
self =
<smiley.tracer.Tracer object at 0x103caff10>
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.143499, u'line_no': 3, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg':
$ smiley monitor
Waiting for incoming data
MESSAGE: ['start_run', {u'command_line': [u'simple.py'], u'run_id':
u'e87302b2-402a-4243-bb27-69a467d4bd8e'}]
Starting new run: [u'simple.py']
MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.142863,
u'line_no': 1,
u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py',
u'func_name': u'<module>', u'arg': None, u'locals': {u'self':
u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line':
[u'simple.py']}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys
command_line =
[u'simple.py']
self =
<smiley.tracer.Tracer object at 0x103caff10>
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.143175,
u'line_no': 1,
u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py',
u'func_name': u'<module>', u'arg': None, u'locals': {u'self':
u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line':
[u'simple.py']}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys
command_line =
[u'simple.py']
self =
<smiley.tracer.Tracer object at 0x103caff10>
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.143499, u'line_no': 3, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg':
MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.144927, u'line_no': 21, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None,
u'locals': {}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 21: def a():
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.145128, u'line_no': 22, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None,
u'locals': {}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 22: print 'args:',
sys.argv
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.145343, u'line_no': 23, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None,
u'locals': {}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 23: b(2)
def start_run(self, run_id, cwd, description,
start_time):
"Record the beginning of a run."
with transaction(self.conn) as c:
c.execute(
"""
INSERT INTO run (id, cwd, description,
start_time)
VALUES
(:id, :cwd, :description, :start_time)
""",
{'id': run_id,
'cwd': cwd,
'description': description,
'start_time': start_time}
)
def _process_message(self, msg):
msg_type, msg_payload = msg
if msg_type == 'start_run':
command_line = ' ‘.join(
msg_payload.get('command_line', []))
self._cwd = msg_payload.get('cwd', '')
if self._cwd:
self._cwd = (self._cwd.rstrip(os.sep) +
os.sep)
self.db.start_run(
run_id=msg_payload.get('run_id'),
cwd=self._cwd,
description=command_line,
start_time=msg_payload.get('timestamp'),
)
elif msg_type == 'end_run':
self.log.info('Finished run')
self.db.end_run(
run_id=msg_payload['run_id'],
end_time=msg_payload.get('timestamp'),
message=msg_payload.get('message'),
traceback=msg_payload.get('traceback'),
)
else:
self.db.trace(
run_id=msg_payload['run_id'],
event=msg_type,
func_name=msg_payload.get('func_name'),
line_no=msg_payload.get('line_no'),
filename=msg_payload.get('filename'),
trace_arg=msg_payload.get('arg'),
locals=msg_payload.get('locals'),
timestamp=msg_payload.get('timestamp'),
)
• Replay past runs
• Complex data types
flickr/Chris Marquardt
import json
import traceback
import types
def _json_special_types(obj):
if isinstance(obj, types.TracebackType):
return traceback.extract_tb(obj)
if isinstance(obj, type):
# We don't want to return classes
return repr(obj)
try:
data = dict(vars(obj))
data['__class__'] = obj.__class__.__name__
data['__module__'] = obj.__class__.__module__
except Exception as err:
data = repr(obj)
return data
def dumps(data):
return json.dumps(data, default=_json_special_types)
?
class EventProcessor(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def start_run(self, run_id, cwd, description,
start_time):
"""Called when a 'start_run' event is seen.
"""
@abc.abstractmethod
def end_run(self, run_id, end_time, message,
traceback):
"""Called when an 'end_run' event is seen.
"""
@abc.abstractmethod
def trace(self, run_id, event,
func_name, line_no, filename,
trace_arg, local_vars,
timestamp):
"""Called when any other event type is seen.
"""
def get_runs(self):
"Return the runs available to browse."
with transaction(self.conn) as c:
c.execute(
"""
SELECT
id, cwd, description, start_time,
end_time, error_message
FROM run
"""
)
return c.fetchall()
def take_action(self, parsed_args):
self.out = output.OutputFormatter(
linecache.getline)
self.db = db.DB(parsed_args.database)
run_details = self.db.get_run(parsed_args.run_id)
self.out.start_run(
run_details.id,
run_details.cwd,
run_details.description,
run_details.start_time,
)
for t in self.db.get_trace(parsed_args.run_id):
self.out.trace(
t.run_id, t.event, t.func_name,
t.line_no, t.filename, t.trace_arg,
t.local_vars, t.timestamp,
)
self.out.end_run(
run_details.id,
run_details.end_time,
run_details.error_message,
None) # run_details.traceback
MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.144927, u'line_no': 21, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None,
u'locals': {}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 21: def a():
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.145128, u'line_no': 22, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None,
u'locals': {}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 22: print 'args:',
sys.argv
MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e',
u'timestamp': 1436367235.145343, u'line_no': 23, u'filename': u'/Users/
dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None,
u'locals': {}}]
/Users/dhellmann/Devel/smiley/scratch/simple.py: 23: b(2)
class DBLineCache(object):
def __init__(self, db, run_id):
self._db = db
self._run_id = run_id
self._files = {}
def getline(self, filename, line_no):
if filename not in self._files:
body = self._db.get_cached_file(
self._run_id, filename)
self._files[filename] = body.splitlines()
try:
return self._files[filename][line_no]
except IndexError:
# Line number is out of range
return ''
def take_action(self, parsed_args):
# Fix import path
cwd = os.getcwd()
if (cwd not in sys.path and
os.curdir not in sys.path):
sys.path.insert(0, cwd)
# Fix command line args
sys.argv = parsed_args.command
# Run the app
p = publisher.Publisher(parsed_args.socket)
t = tracer.Tracer(p)
t.run(parsed_args.command)
def take_action(self, parsed_args):
# Fix import path
cwd = os.getcwd()
if (cwd not in sys.path and
os.curdir not in sys.path):
sys.path.insert(0, cwd)
# Fix command line args
sys.argv = parsed_args.command
# Run the app
if parsed_args.mode == 'remote':
p = publisher.Publisher(parsed_args.socket)
else:
p = db.DB(parsed_args.database)
t = tracer.Tracer(p)
t.run(parsed_args.command)
1.ZMQ
2.Tracing
3.Command line interface
4.Database
5.Complex objects
6.EventProcessor API
7.Replay command
8.Store source files
9.Local database
1.ZMQ
2.Tracing
3.Command line interface
4.Database
5.Complex objects
6.EventProcessor API
7.Replay command
8.Store source files
9.Local database
UI Tools
class FileController(RestController):
@expose(generic=True, template='file.html')
@nav.active_section('runs')
def get_one(self, run_id, file_id):
filename, body = 
request.db.get_cached_file_by_id(run_id,
file_id)
run = request.db.get_run(run_id)
lexer = guess_lexer_for_filename(filename, body)
formatter = HtmlFormatter(linenos=True)
styled_body = highlight(body, lexer, formatter)
return {
'run_id': run_id,
'run': run,
'filename': filename,
'body': body,
'styled_body': styled_body,
}
class StyledLineCache(object):
def __init__(self, db, run_id):
self._db = db
self._run_id = run_id
self._files = {}
EXPECTED_PREFIX = '<div class="highlight"><pre>'
EXPECTED_SUFFIX = '</pre></div>'
def getline(self, filename, line_no):
if filename not in self._files:
body = self._db.get_cached_file(self._run_id,
filename)
styled_body = apply_style(filename, body,
linenos=False)
start = len(self.EXPECTED_PREFIX)
end = -1 * (len(self.EXPECTED_SUFFIX) + 1)
middle_body = styled_body[start:end].rstrip('n')
self._files[filename] = middle_body.splitlines()
try:
return self._files[filename][line_no-1]
except IndexError:
# Line number is out of range
return ''
✓ Web UI
✓ Profiling Data
✓ Call Graph
✓ Syntax Highlighting
• Only Changed Variables
• Comments
def _mk_seq(d):
return sorted(
(k, pformat(v, width=20))
for k, v in d.iteritems()
)
def get_variable_changes(older, newer):
s_a = _mk_seq(older)
s_b = _mk_seq(newer)
matcher = difflib.SequenceMatcher(None, s_a, s_b)
for tag, i1, i2, j1, j2 in matcher.get_opcodes():
if tag in {'insert', 'replace'}:
for i in s_b[j1:j2]:
yield i
Other Features
Tracing
Threaded
Applications
Static
HTML
Reports
DB
Export/
Import
Pagination
in
Web UI
Other Features
Tracing
Threaded
Applications
Static
HTML
Reports
DB
Export/
Import
Pagination
in
Web UI
0
1000
2000
3000
4000
2013-05-25
2013-05-26
2013-05-27
2013-05-28
2013-06-02
2013-06-03
2013-06-05
2013-06-06
2013-06-08
2013-06-16
2013-06-23
2013-07-14
2013-07-27
2013-07-28
2013-09-01
2013-12-28
2013-12-29
2013-12-30
2014-01-04
2014-01-12
2014-07-06
2014-08-01
0
1000
2000
3000
4000
2013-05-25
2013-05-26
2013-05-27
2013-05-28
2013-06-02
2013-06-03
2013-06-05
2013-06-06
2013-06-08
2013-06-16
2013-06-23
2013-07-14
2013-07-27
2013-07-28
2013-09-01
2013-12-28
2013-12-29
2013-12-30
2014-01-04
2014-01-12
2014-07-06
2014-08-01
0
1000
2000
3000
4000
2013-05-25
2013-05-26
2013-05-27
2013-05-28
2013-06-02
2013-06-03
2013-06-05
2013-06-06
2013-06-08
2013-06-16
2013-06-23
2013-07-14
2013-07-27
2013-07-28
2013-09-01
2013-12-28
2013-12-29
2013-12-30
2014-01-04
2014-01-12
2014-07-06
2014-08-01
• Performance
• Standard I/O
• GUI
• Compare runs
flickr/Mike Mozart
Freenode: dhellmann
doug@doughellmann.com
github.com/dhellmann/smiley
smiley.readthedocs.org
How I Built a Power Debugger Out of the Standard Library and Things I Found on the Internet

More Related Content

What's hot

How to stand on the shoulders of giants
How to stand on the shoulders of giantsHow to stand on the shoulders of giants
How to stand on the shoulders of giants
Ian Barber
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
Eleanor McHugh
 
Créer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heureCréer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heure
Amaury Bouchard
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
Wim Godden
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 WorldFabien Potencier
 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Ralf Eggert
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your projectMichelangelo van Dam
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoIntroduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoMasahiro Nagano
 
Inside a Digital Collection: Historic Clothing in Omeka
Inside a Digital Collection: Historic Clothing in OmekaInside a Digital Collection: Historic Clothing in Omeka
Inside a Digital Collection: Historic Clothing in Omeka
Arden Kirkland
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
Mark Baker
 
Micropage in microtime using microframework
Micropage in microtime using microframeworkMicropage in microtime using microframework
Micropage in microtime using microframework
Radek Benkel
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
Ian Barber
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Masahiro Nagano
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
Michelangelo van Dam
 
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The Answer
Ian Barber
 
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Mail.ru Group
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
Jakub Zalas
 

What's hot (20)

How to stand on the shoulders of giants
How to stand on the shoulders of giantsHow to stand on the shoulders of giants
How to stand on the shoulders of giants
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
 
Créer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heureCréer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heure
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your project
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoIntroduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
 
Inside a Digital Collection: Historic Clothing in Omeka
Inside a Digital Collection: Historic Clothing in OmekaInside a Digital Collection: Historic Clothing in Omeka
Inside a Digital Collection: Historic Clothing in Omeka
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Micropage in microtime using microframework
Micropage in microtime using microframeworkMicropage in microtime using microframework
Micropage in microtime using microframework
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
 
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The Answer
 
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Inc
IncInc
Inc
 

Similar to How I Built a Power Debugger Out of the Standard Library and Things I Found on the Internet

Ansible tips & tricks
Ansible tips & tricksAnsible tips & tricks
Ansible tips & tricks
bcoca
 
Monitoring with Syslog and EventMachine (RailswayConf 2012)
Monitoring  with  Syslog and EventMachine (RailswayConf 2012)Monitoring  with  Syslog and EventMachine (RailswayConf 2012)
Monitoring with Syslog and EventMachine (RailswayConf 2012)Wooga
 
Streaming Way to Webscale: How We Scale Bitly via Streaming
Streaming Way to Webscale: How We Scale Bitly via StreamingStreaming Way to Webscale: How We Scale Bitly via Streaming
Streaming Way to Webscale: How We Scale Bitly via Streaming
All Things Open
 
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak   CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
PROIDEA
 
Primeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SP
Primeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SPPrimeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SP
Primeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SP
Zabbix BR
 
Map/Confused? A practical approach to Map/Reduce with MongoDB
Map/Confused? A practical approach to Map/Reduce with MongoDBMap/Confused? A practical approach to Map/Reduce with MongoDB
Map/Confused? A practical approach to Map/Reduce with MongoDB
Uwe Printz
 
Monitoring with Syslog and EventMachine
Monitoring with Syslog and EventMachineMonitoring with Syslog and EventMachine
Monitoring with Syslog and EventMachine
Wooga
 
Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기
JeongHun Byeon
 
libuv, NodeJS and everything in between
libuv, NodeJS and everything in betweenlibuv, NodeJS and everything in between
libuv, NodeJS and everything in between
Saúl Ibarra Corretgé
 
Memory Manglement in Raku
Memory Manglement in RakuMemory Manglement in Raku
Memory Manglement in Raku
Workhorse Computing
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
Mustafa TURAN
 
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
IstSec'14 - İbrahim BALİÇ -  Automated Malware AnalysisIstSec'14 - İbrahim BALİÇ -  Automated Malware Analysis
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
BGA Cyber Security
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con Python
PyCon Italia
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by default
Slawomir Jasek
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by default
SecuRing
 
Nagios Conference 2014 - Rodrigo Faria - Developing your Plugin
Nagios Conference 2014 - Rodrigo Faria - Developing your PluginNagios Conference 2014 - Rodrigo Faria - Developing your Plugin
Nagios Conference 2014 - Rodrigo Faria - Developing your Plugin
Nagios
 
Interface de Voz con Rails
Interface de Voz con RailsInterface de Voz con Rails
Interface de Voz con RailsSvet Ivantchev
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Francois Zaninotto
 

Similar to How I Built a Power Debugger Out of the Standard Library and Things I Found on the Internet (20)

Ansible tips & tricks
Ansible tips & tricksAnsible tips & tricks
Ansible tips & tricks
 
Monitoring with Syslog and EventMachine (RailswayConf 2012)
Monitoring  with  Syslog and EventMachine (RailswayConf 2012)Monitoring  with  Syslog and EventMachine (RailswayConf 2012)
Monitoring with Syslog and EventMachine (RailswayConf 2012)
 
Streaming Way to Webscale: How We Scale Bitly via Streaming
Streaming Way to Webscale: How We Scale Bitly via StreamingStreaming Way to Webscale: How We Scale Bitly via Streaming
Streaming Way to Webscale: How We Scale Bitly via Streaming
 
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak   CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
 
Primeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SP
Primeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SPPrimeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SP
Primeiros Passos na API do Zabbix com Python - 2º ZABBIX MEETUP DO INTERIOR-SP
 
Tt subtemplates-caching
Tt subtemplates-cachingTt subtemplates-caching
Tt subtemplates-caching
 
Map/Confused? A practical approach to Map/Reduce with MongoDB
Map/Confused? A practical approach to Map/Reduce with MongoDBMap/Confused? A practical approach to Map/Reduce with MongoDB
Map/Confused? A practical approach to Map/Reduce with MongoDB
 
Monitoring with Syslog and EventMachine
Monitoring with Syslog and EventMachineMonitoring with Syslog and EventMachine
Monitoring with Syslog and EventMachine
 
The Art of Grey-Box Attack
The Art of Grey-Box AttackThe Art of Grey-Box Attack
The Art of Grey-Box Attack
 
Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기
 
libuv, NodeJS and everything in between
libuv, NodeJS and everything in betweenlibuv, NodeJS and everything in between
libuv, NodeJS and everything in between
 
Memory Manglement in Raku
Memory Manglement in RakuMemory Manglement in Raku
Memory Manglement in Raku
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
 
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
IstSec'14 - İbrahim BALİÇ -  Automated Malware AnalysisIstSec'14 - İbrahim BALİÇ -  Automated Malware Analysis
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con Python
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by default
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by default
 
Nagios Conference 2014 - Rodrigo Faria - Developing your Plugin
Nagios Conference 2014 - Rodrigo Faria - Developing your PluginNagios Conference 2014 - Rodrigo Faria - Developing your Plugin
Nagios Conference 2014 - Rodrigo Faria - Developing your Plugin
 
Interface de Voz con Rails
Interface de Voz con RailsInterface de Voz con Rails
Interface de Voz con Rails
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 

More from doughellmann

Reno: A new way to manage release notes
Reno: A new way to manage release notesReno: A new way to manage release notes
Reno: A new way to manage release notes
doughellmann
 
Reno A New Way to Manage Release Notes
Reno   A New Way to Manage Release NotesReno   A New Way to Manage Release Notes
Reno A New Way to Manage Release Notes
doughellmann
 
How OpenStack Makes Python Better (and vice-versa)
How OpenStack Makes Python Better (and vice-versa)How OpenStack Makes Python Better (and vice-versa)
How OpenStack Makes Python Better (and vice-versa)
doughellmann
 
Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...
Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...
Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...
doughellmann
 
Herding cats into boxes
Herding cats into boxesHerding cats into boxes
Herding cats into boxes
doughellmann
 
OpenStack 5th Birthday
OpenStack 5th BirthdayOpenStack 5th Birthday
OpenStack 5th Birthday
doughellmann
 
Regexes and-performance-testing
Regexes and-performance-testingRegexes and-performance-testing
Regexes and-performance-testing
doughellmann
 
OpenStack Atlanta-2014-12-18
OpenStack Atlanta-2014-12-18OpenStack Atlanta-2014-12-18
OpenStack Atlanta-2014-12-18
doughellmann
 
Taking the Long View: How the Oslo Program Reduces Technical Debt
Taking the Long View: How the Oslo Program Reduces Technical DebtTaking the Long View: How the Oslo Program Reduces Technical Debt
Taking the Long View: How the Oslo Program Reduces Technical Debt
doughellmann
 
Oslo Program Overview, OpenStack Atlanta
Oslo Program Overview, OpenStack AtlantaOslo Program Overview, OpenStack Atlanta
Oslo Program Overview, OpenStack Atlanta
doughellmann
 
Dynamic Code Patterns: Extending Your Applications with Plugins
Dynamic Code Patterns: Extending Your Applications with PluginsDynamic Code Patterns: Extending Your Applications with Plugins
Dynamic Code Patterns: Extending Your Applications with Plugins
doughellmann
 
Better Documentation Through Automation: Creating docutils & Sphinx Extensions
Better Documentation Through Automation: Creating docutils & Sphinx ExtensionsBetter Documentation Through Automation: Creating docutils & Sphinx Extensions
Better Documentation Through Automation: Creating docutils & Sphinx Extensions
doughellmann
 
Hidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard LibraryHidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard Library
doughellmann
 
An Introduction to the Zen of Python
An Introduction to the Zen of PythonAn Introduction to the Zen of Python
An Introduction to the Zen of Python
doughellmann
 

More from doughellmann (14)

Reno: A new way to manage release notes
Reno: A new way to manage release notesReno: A new way to manage release notes
Reno: A new way to manage release notes
 
Reno A New Way to Manage Release Notes
Reno   A New Way to Manage Release NotesReno   A New Way to Manage Release Notes
Reno A New Way to Manage Release Notes
 
How OpenStack Makes Python Better (and vice-versa)
How OpenStack Makes Python Better (and vice-versa)How OpenStack Makes Python Better (and vice-versa)
How OpenStack Makes Python Better (and vice-versa)
 
Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...
Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...
Rolling with the Times: Using wheels, pbr, and Twine for Distributing and Ins...
 
Herding cats into boxes
Herding cats into boxesHerding cats into boxes
Herding cats into boxes
 
OpenStack 5th Birthday
OpenStack 5th BirthdayOpenStack 5th Birthday
OpenStack 5th Birthday
 
Regexes and-performance-testing
Regexes and-performance-testingRegexes and-performance-testing
Regexes and-performance-testing
 
OpenStack Atlanta-2014-12-18
OpenStack Atlanta-2014-12-18OpenStack Atlanta-2014-12-18
OpenStack Atlanta-2014-12-18
 
Taking the Long View: How the Oslo Program Reduces Technical Debt
Taking the Long View: How the Oslo Program Reduces Technical DebtTaking the Long View: How the Oslo Program Reduces Technical Debt
Taking the Long View: How the Oslo Program Reduces Technical Debt
 
Oslo Program Overview, OpenStack Atlanta
Oslo Program Overview, OpenStack AtlantaOslo Program Overview, OpenStack Atlanta
Oslo Program Overview, OpenStack Atlanta
 
Dynamic Code Patterns: Extending Your Applications with Plugins
Dynamic Code Patterns: Extending Your Applications with PluginsDynamic Code Patterns: Extending Your Applications with Plugins
Dynamic Code Patterns: Extending Your Applications with Plugins
 
Better Documentation Through Automation: Creating docutils & Sphinx Extensions
Better Documentation Through Automation: Creating docutils & Sphinx ExtensionsBetter Documentation Through Automation: Creating docutils & Sphinx Extensions
Better Documentation Through Automation: Creating docutils & Sphinx Extensions
 
Hidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard LibraryHidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard Library
 
An Introduction to the Zen of Python
An Introduction to the Zen of PythonAn Introduction to the Zen of Python
An Introduction to the Zen of Python
 

Recently uploaded

Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
Tendenci - The Open Source AMS (Association Management Software)
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Natan Silnitsky
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Shahin Sheidaei
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
takuyayamamoto1800
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
Ortus Solutions, Corp
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
vrstrong314
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
AMB-Review
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Globus
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus
 

Recently uploaded (20)

Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
 

How I Built a Power Debugger Out of the Standard Library and Things I Found on the Internet

  • 1. How I Built a Power Debugger Out of the Standard Library and Things I Found on the Internet Doug Hellmann PyCon US 2016
  • 2. I Built a Power Debugger! Doug Hellmann PyCon US 2016
  • 3. How I Built a Power Debugger! Doug Hellmann PyCon US 2016
  • 5.
  • 6.
  • 7. Features • Record calls with data • Remote monitoring, local analysis • Browse history • Learn new tools flickr/Kangrex
  • 8.
  • 9. class Publisher(object): def __init__(self, endpoint, high_water_mark=10000): self.context = zmq.Context() self.pub_socket = self.context.socket(zmq.PUSH) self.pub_socket.bind(endpoint) self.pub_socket.identity = 'publisher' self.pub_socket.hwm = high_water_mark def send(self, msg_type, data): msg = [ msg_type, json.dumps(data, default=self._json_special_types), ] self.pub_socket.send_multipart(msg)
  • 10. def trace_calls(self, frame, event, arg): co = frame.f_code filename = co.co_filename if filename in (__file__,): # Ignore ourself return self._send_notice(frame, event, arg) return self.trace_calls
  • 11. def _send_notice(self, frame, event, arg): co = frame.f_code func_name = co.co_name line_no = frame.f_lineno filename = os.path.abspath(co.co_filename) for d in IGNORE_DIRS: if filename.startswith(d): return # …
  • 12. # … interesting_locals = { n: v for n, v in frame.f_locals.items() if (not inspect.ismodule(v) and not inspect.isfunction(v) and not inspect.ismethod(v) and (n[:2] != '__' and n[-2:] != '__')) } # …
  • 13. # … self.publisher.send( event, {'func_name': func_name, 'line_no': line_no, 'filename': filename, 'arg': arg, 'locals': interesting_locals, 'timestamp': time.time(), 'run_id': self.run_id, })
  • 14. $ smiley help usage: smiley [--version] [-v] [--log-file LOG_FILE] [-q] [-h] [--debug] smiley spies on your apps as they run optional arguments: --version show program's version number and exit -v, --verbose Increase verbosity of output. --log-file LOG_FILE Specify a file to log output. -q, --quiet suppress output except warnings -h, --help show this help message and exit --debug show tracebacks on errors Commands: complete print bash completion command help print detailed help for another command monitor Listen for running programs and show their progress. run Run another program with monitoring enabled.
  • 15. $ smiley help run usage: smiley run [-h] [--socket SOCKET] command [command ...] Run another program with monitoring enabled. positional arguments: command the command to spy on optional arguments: -h, --help show this help message and exit --socket SOCKET URL for the socket where the listener will be (tcp://127.0.0.1:5556)
  • 16. $ smiley help monitor usage: smiley monitor [-h] [--socket SOCKET] Listen for running programs and show their progress. optional arguments: -h, --help show this help message and exit --socket SOCKET URL for the socket where to monitor on (tcp://127.0.0.1:5556)
  • 17. def _process_message(self, msg): print 'MESSAGE:', msg msg_type, msg_payload = msg if msg_type == 'start_run': print (‘Starting new run:', msg_payload.get(‘command_line')) elif msg_type == 'end_run': print 'Finished run' else: line = linecache.getline(msg_payload['filename'], msg_payload['line_no']).rstrip() if msg_type == 'return': print '%s:%4s: return>>> %s' % ( msg_payload['filename'], msg_payload[‘line_no'], msg_payload['arg']) else: print '%s:%4s: %s' % ( msg_payload['filename'], msg_payload[‘line_no'], line) if msg_payload.get('locals'): for n, v in sorted(msg_payload['locals'].items()): print '%s %s = %s' % ( ' ' * len(msg_payload['filename']), n, v, ) print
  • 18. def gen(m): for i in xrange(m): yield i def c(input): print 'input =', input data = list(gen(input)) print 'Leaving c()' def b(arg): val = arg * 5 c(val) print 'Leaving b()' return val def a(): print 'args:', sys.argv b(2) print 'Leaving a()' a()
  • 19. $ smiley monitor Waiting for incoming data MESSAGE: ['start_run', {u'command_line': [u'simple.py'], u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e'}] Starting new run: [u'simple.py'] MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.142863, u'line_no': 1, u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg': None, u'locals': {u'self': u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line': [u'simple.py']}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys command_line = [u'simple.py'] self = <smiley.tracer.Tracer object at 0x103caff10> MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.143175, u'line_no': 1, u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg': None, u'locals': {u'self': u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line': [u'simple.py']}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys command_line = [u'simple.py'] self = <smiley.tracer.Tracer object at 0x103caff10> MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.143499, u'line_no': 3, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg':
  • 20. $ smiley monitor Waiting for incoming data MESSAGE: ['start_run', {u'command_line': [u'simple.py'], u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e'}] Starting new run: [u'simple.py'] MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.142863, u'line_no': 1, u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg': None, u'locals': {u'self': u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line': [u'simple.py']}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys command_line = [u'simple.py'] self = <smiley.tracer.Tracer object at 0x103caff10> MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.143175, u'line_no': 1, u'filename': u'/Users/dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg': None, u'locals': {u'self': u'<smiley.tracer.Tracer object at 0x103caff10>', u'command_line': [u'simple.py']}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 1: import sys command_line = [u'simple.py'] self = <smiley.tracer.Tracer object at 0x103caff10> MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.143499, u'line_no': 3, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'<module>', u'arg':
  • 21. MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.144927, u'line_no': 21, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None, u'locals': {}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 21: def a(): MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.145128, u'line_no': 22, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None, u'locals': {}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 22: print 'args:', sys.argv MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.145343, u'line_no': 23, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None, u'locals': {}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 23: b(2)
  • 22.
  • 23.
  • 24. def start_run(self, run_id, cwd, description, start_time): "Record the beginning of a run." with transaction(self.conn) as c: c.execute( """ INSERT INTO run (id, cwd, description, start_time) VALUES (:id, :cwd, :description, :start_time) """, {'id': run_id, 'cwd': cwd, 'description': description, 'start_time': start_time} )
  • 25. def _process_message(self, msg): msg_type, msg_payload = msg if msg_type == 'start_run': command_line = ' ‘.join( msg_payload.get('command_line', [])) self._cwd = msg_payload.get('cwd', '') if self._cwd: self._cwd = (self._cwd.rstrip(os.sep) + os.sep) self.db.start_run( run_id=msg_payload.get('run_id'), cwd=self._cwd, description=command_line, start_time=msg_payload.get('timestamp'), )
  • 26. elif msg_type == 'end_run': self.log.info('Finished run') self.db.end_run( run_id=msg_payload['run_id'], end_time=msg_payload.get('timestamp'), message=msg_payload.get('message'), traceback=msg_payload.get('traceback'), ) else: self.db.trace( run_id=msg_payload['run_id'], event=msg_type, func_name=msg_payload.get('func_name'), line_no=msg_payload.get('line_no'), filename=msg_payload.get('filename'), trace_arg=msg_payload.get('arg'), locals=msg_payload.get('locals'), timestamp=msg_payload.get('timestamp'), )
  • 27. • Replay past runs • Complex data types flickr/Chris Marquardt
  • 28. import json import traceback import types def _json_special_types(obj): if isinstance(obj, types.TracebackType): return traceback.extract_tb(obj) if isinstance(obj, type): # We don't want to return classes return repr(obj) try: data = dict(vars(obj)) data['__class__'] = obj.__class__.__name__ data['__module__'] = obj.__class__.__module__ except Exception as err: data = repr(obj) return data def dumps(data): return json.dumps(data, default=_json_special_types)
  • 29. ?
  • 30. class EventProcessor(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def start_run(self, run_id, cwd, description, start_time): """Called when a 'start_run' event is seen. """ @abc.abstractmethod def end_run(self, run_id, end_time, message, traceback): """Called when an 'end_run' event is seen. """ @abc.abstractmethod def trace(self, run_id, event, func_name, line_no, filename, trace_arg, local_vars, timestamp): """Called when any other event type is seen. """
  • 31. def get_runs(self): "Return the runs available to browse." with transaction(self.conn) as c: c.execute( """ SELECT id, cwd, description, start_time, end_time, error_message FROM run """ ) return c.fetchall()
  • 32. def take_action(self, parsed_args): self.out = output.OutputFormatter( linecache.getline) self.db = db.DB(parsed_args.database) run_details = self.db.get_run(parsed_args.run_id) self.out.start_run( run_details.id, run_details.cwd, run_details.description, run_details.start_time, ) for t in self.db.get_trace(parsed_args.run_id): self.out.trace( t.run_id, t.event, t.func_name, t.line_no, t.filename, t.trace_arg, t.local_vars, t.timestamp, ) self.out.end_run( run_details.id, run_details.end_time, run_details.error_message, None) # run_details.traceback
  • 33. MESSAGE: ['call', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.144927, u'line_no': 21, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None, u'locals': {}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 21: def a(): MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.145128, u'line_no': 22, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None, u'locals': {}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 22: print 'args:', sys.argv MESSAGE: ['line', {u'run_id': u'e87302b2-402a-4243-bb27-69a467d4bd8e', u'timestamp': 1436367235.145343, u'line_no': 23, u'filename': u'/Users/ dhellmann/Devel/smiley/scratch/simple.py', u'func_name': u'a', u'arg': None, u'locals': {}}] /Users/dhellmann/Devel/smiley/scratch/simple.py: 23: b(2)
  • 34. class DBLineCache(object): def __init__(self, db, run_id): self._db = db self._run_id = run_id self._files = {} def getline(self, filename, line_no): if filename not in self._files: body = self._db.get_cached_file( self._run_id, filename) self._files[filename] = body.splitlines() try: return self._files[filename][line_no] except IndexError: # Line number is out of range return ''
  • 35. def take_action(self, parsed_args): # Fix import path cwd = os.getcwd() if (cwd not in sys.path and os.curdir not in sys.path): sys.path.insert(0, cwd) # Fix command line args sys.argv = parsed_args.command # Run the app p = publisher.Publisher(parsed_args.socket) t = tracer.Tracer(p) t.run(parsed_args.command)
  • 36. def take_action(self, parsed_args): # Fix import path cwd = os.getcwd() if (cwd not in sys.path and os.curdir not in sys.path): sys.path.insert(0, cwd) # Fix command line args sys.argv = parsed_args.command # Run the app if parsed_args.mode == 'remote': p = publisher.Publisher(parsed_args.socket) else: p = db.DB(parsed_args.database) t = tracer.Tracer(p) t.run(parsed_args.command)
  • 37. 1.ZMQ 2.Tracing 3.Command line interface 4.Database 5.Complex objects 6.EventProcessor API 7.Replay command 8.Store source files 9.Local database
  • 38. 1.ZMQ 2.Tracing 3.Command line interface 4.Database 5.Complex objects 6.EventProcessor API 7.Replay command 8.Store source files 9.Local database
  • 40.
  • 41.
  • 42.
  • 43. class FileController(RestController): @expose(generic=True, template='file.html') @nav.active_section('runs') def get_one(self, run_id, file_id): filename, body = request.db.get_cached_file_by_id(run_id, file_id) run = request.db.get_run(run_id) lexer = guess_lexer_for_filename(filename, body) formatter = HtmlFormatter(linenos=True) styled_body = highlight(body, lexer, formatter) return { 'run_id': run_id, 'run': run, 'filename': filename, 'body': body, 'styled_body': styled_body, }
  • 44.
  • 45. class StyledLineCache(object): def __init__(self, db, run_id): self._db = db self._run_id = run_id self._files = {} EXPECTED_PREFIX = '<div class="highlight"><pre>' EXPECTED_SUFFIX = '</pre></div>' def getline(self, filename, line_no): if filename not in self._files: body = self._db.get_cached_file(self._run_id, filename) styled_body = apply_style(filename, body, linenos=False) start = len(self.EXPECTED_PREFIX) end = -1 * (len(self.EXPECTED_SUFFIX) + 1) middle_body = styled_body[start:end].rstrip('n') self._files[filename] = middle_body.splitlines() try: return self._files[filename][line_no-1] except IndexError: # Line number is out of range return ''
  • 46.
  • 47.
  • 48.
  • 49.
  • 50. ✓ Web UI ✓ Profiling Data ✓ Call Graph ✓ Syntax Highlighting • Only Changed Variables • Comments
  • 51. def _mk_seq(d): return sorted( (k, pformat(v, width=20)) for k, v in d.iteritems() ) def get_variable_changes(older, newer): s_a = _mk_seq(older) s_b = _mk_seq(newer) matcher = difflib.SequenceMatcher(None, s_a, s_b) for tag, i1, i2, j1, j2 in matcher.get_opcodes(): if tag in {'insert', 'replace'}: for i in s_b[j1:j2]: yield i
  • 52.
  • 53.
  • 54.
  • 55.
  • 61. • Performance • Standard I/O • GUI • Compare runs flickr/Mike Mozart