Книга: Программирование на языке Ruby

11.3.10. Мониторинг выполнения программы

11.3.10. Мониторинг выполнения программы

Программа на Ruby может следить за собственным выполнением. У этой возможности есть много применений; интересующийся читатель может заглянуть в исходные тексты программ debug.rb, profile.rb и tracer.rb. С ее помощью можно даже создать библиотеку для «проектирования по контракту» (design-by-contract, DBC), хотя наиболее популярная в данный момент библиотека такого рода этим средством не пользуется.

Интересно, что этот фокус реализован целиком на Ruby. Мы пользуемся методом set_trace_func, который позволяет вызывать указанный блок при возникновении значимых событий в ходе исполнения программы. В справочном руководстве описывается последовательность вызова set_trace_func, поэтому здесь мы ограничимся простым примером:

def meth(n)
 sum = 0
 for i in 1..n
  sum += i
 end
 sum
end
set_trace_func(proc do |event, file, line,
 id, binding, klass, *rest|
 printf "%8s %s:%d %s/%sn", event, file, line,
  klass, id
 end)
meth(2)

Отметим, что здесь соблюдается стандартное соглашение о заключении многострочного блока в операторные скобки do-end. Круглые скобки обязательны из-за особенностей синтаксического анализатора Ruby. Можно было бы, конечно, вместо этого поставить фигурные скобки.

Вот что будет напечатано в результате выполнения этого кода:

line prog.rb:13 false/
    call prog.rb:1 Object/meth
    line prog.rb:2 Object/meth
    line prog.rb:3 Object/meth
  c-call prog.rb:3 Range/each
    line prog.rb:4 Object/meth
  c-call prog.rb:4 Fixnum/+
c-return prog.rb:4 Fixnum/+
    line prog.rb:4 Object/meth
  c-call prog.rb:4 Fixnum/+
c-return prog.rb:4 Fixnum/+
c-return prog.rb:4 Range/each
    line prog.rb:6 Object/meth
  return prog.rb:6 Object/meth

С этим методом тесно связан метод Kernel#trace_var, который вызывает указанный блок при каждом присваивании значения глобальной переменной.

Предположим, что вам нужно извне протрассировать выполнение программы в целях отладки. Проще всего воспользоваться для этого библиотекой tracer. Пусть имеется следующая программа prog.rb:

def meth(n)
 (1..n).each {|i| puts i}
end
meth(3)

Можно запустить tracer из командной строки:

% ruby -r tracer prog.rb
#0:prog.rb:1::-:       def meth(n)
#0:prog.rb:1:Module:>: def meth(n)
#0:prog.rb:1:Module:<: def meth(n)
#0:prog.rb:8::-:       meth(2)
#0:prog.rb:1:Object:>: def meth(n)
#0:prog.rb:2:Object:-: sum = 0
#0:prog.rb:3:Object:-: for i in 1..n
#0:prog.rb:3:Range:>:  for i in 1..n
#0:prog.rb:4:Object:-: sum += i
#0:prog.rb:4:Fixnum:>: sum += i
#0:prog.rb:4:Fixnum:<: sum += i
#0:prog.rb:4:Object:-: sum += i
#0:prog.rb:4:Fixnum:>: sum += i
#0:prog.rb:4:Fixnum:<: sum += i
#0:prog.rb:4:Range:<:  sum += i
#0:prog.rb:6:Object:-: sum
#0:prog.rb:6:Object:<: sum

Программа tracer выводит номер потока, имя файла и номер строки, имя класса, тип события и исполняемую строку исходного текста трассируемой программы. Бывают следующие типы событий: '-' — исполняется строка исходного текста, '>' — вызов, '<' — возврат, 'С' — класс, 'Е' — конец. (Если вы автоматически включите эту библиотеку с помощью переменной окружения RUBYOPT или каким-то иным способом, то может быть напечатано много тысяч строк.)

Оглавление книги


Генерация: 0.038. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз