Привет читатель.
В процессе разработки и дебаггинга, по крайней мере у меня раньше, код зачастую обрастает всякого рода условными console.log вида:
Их постоянно нужно включать/отключать, перегрупировывать опции, в итоге появляются всякие dbDebug, validateDebug, authDebug, и далее, насколько хватит фантазии. Рано или поздно появляется желание выводить все это не в консоль, а скажем в различные файлы, или к примеру какой-нибудь admin tool на socket.io. Собирать и менять все это во всем проекте задача нетривиальная.
Под катом я расскажу какое решение применил я на текущем рабочем проекте.
Итак, что нам нужно? Некий централизованный обработчик отладочных данных. Решение, предлагаемое мной, пришло ко мне, когда я писал soket.io admin tool для упрощения административных операций (чтение логов, очистка базы(нетривиальная задача для dynamoDB) в планах запилить еще многое).
Так вот, было 2 возможности:
— клиент обращается к серверу, а тот выдает ему порцию «свежих» данных
— сервер сам рассылает всю информацию всем своим подключенным клиентам
Первый вариант я сразу отбросил, так как понятие «свежести» данных меня отпугнуло: сервер должен знать для какого клиента, какие данные являются свежими, да и вообще, это означает необходимость хранения данных, а в моей задаче это не требуется по умолчанию.
А вот второй вариант привлек меня своей простотой и удобством.
Здесь мне просто-напросто нужно было вспомнить о том, что есть в природе такой паттерн проектирования, как Observer.
Итак приступим:
Создаем простенький объект, например profiler…
Нам нужно где-то хранить обработчики данных, создаем массив:
Также нам нужна возможность подписываться и отписываться от рассылаемых данных:
Все, мы имеем возможность добавлять/удалять обработчики отладочных данных, дело за малым: их нужно вызывать:
Просто пробегаемся по всем своим функциям-подписчикам и вызываем их с параметром переданным в announce.
Это невероятно гибкое решение, теперь мы можем писать любые обработчики данных, но для начала приведу примеры из своего проекта:
В общем, тут на что фантазии хватит, я решил классифицировать типы данных всегда передавая type, а в обработчиках у меня есть возможность фильтровать их как мне заблагорассудится. Например, напишем логирование в файлы:
Как видите, очень гибко и удобно, надеюсь кому-нибудь это поможет в нелегком деле рефакторинга.
Спасибо за внимание!
PS: Для тех, кому не нравится неприватность свойства clients в нашем профайлере, всегда можно( и нужно ) сделать так:
В процессе разработки и дебаггинга, по крайней мере у меня раньше, код зачастую обрастает всякого рода условными console.log вида:
if(config.debug) console.log(method, params); ... if(config.profiler) console.log(method, (new Date).getTime()-start_time); и тп.
Их постоянно нужно включать/отключать, перегрупировывать опции, в итоге появляются всякие dbDebug, validateDebug, authDebug, и далее, насколько хватит фантазии. Рано или поздно появляется желание выводить все это не в консоль, а скажем в различные файлы, или к примеру какой-нибудь admin tool на socket.io. Собирать и менять все это во всем проекте задача нетривиальная.
Под катом я расскажу какое решение применил я на текущем рабочем проекте.
Итак, что нам нужно? Некий централизованный обработчик отладочных данных. Решение, предлагаемое мной, пришло ко мне, когда я писал soket.io admin tool для упрощения административных операций (чтение логов, очистка базы(нетривиальная задача для dynamoDB) в планах запилить еще многое).
Так вот, было 2 возможности:
— клиент обращается к серверу, а тот выдает ему порцию «свежих» данных
— сервер сам рассылает всю информацию всем своим подключенным клиентам
Первый вариант я сразу отбросил, так как понятие «свежести» данных меня отпугнуло: сервер должен знать для какого клиента, какие данные являются свежими, да и вообще, это означает необходимость хранения данных, а в моей задаче это не требуется по умолчанию.
А вот второй вариант привлек меня своей простотой и удобством.
Здесь мне просто-напросто нужно было вспомнить о том, что есть в природе такой паттерн проектирования, как Observer.
Итак приступим:
Создаем простенький объект, например profiler…
var profiler = {}
Нам нужно где-то хранить обработчики данных, создаем массив:
profiler.clients = [];
Также нам нужна возможность подписываться и отписываться от рассылаемых данных:
profiler.subscribe = function(id, next){ this.clients[id] = next; } profiler.unsubscribe = function(id){ delete this.clients[id] }
Все, мы имеем возможность добавлять/удалять обработчики отладочных данных, дело за малым: их нужно вызывать:
profiler.announce = function(data){ for(var id in this.clients) this.clients[id](data); }
Просто пробегаемся по всем своим функциям-подписчикам и вызываем их с параметром переданным в announce.
Это невероятно гибкое решение, теперь мы можем писать любые обработчики данных, но для начала приведу примеры из своего проекта:
Все вызовы: if(condition) console.log(data); я заменил на что-то вроде: profiler.announce({ type: condition, data, data }); или profiler.announce({ type: 'dynamoDB', query: query, responsse: response, time: (new Date).getTime()-start });
В общем, тут на что фантазии хватит, я решил классифицировать типы данных всегда передавая type, а в обработчиках у меня есть возможность фильтровать их как мне заблагорассудится. Например, напишем логирование в файлы:
profiler.subscribe('file logging', function(data){ var filename = ''; switch(data.type){ case 'dynamoDB': filename = 'dynamoDB.log'; break; case 'debug': filename = 'debug.log'; break; case 'bug': filename = 'error.log'; break; default: filename = 'other.log'; break; } appendToFile(filename, JSON.stringify(data)); }) а баги отправим на почту: profiler.subscribe('bugs mail',function(data){ if(data.type == 'bug') sendEmail(config.admin, data.method, data.error + '\n' + data.stack + '\n'); }) ну и выведем все в консоль: profiler.subscribe('console', console.log); а также подпишем на эти данные socket.io profiler.subscribe(socket.id, function(data){ socket.json.send({'event': 'logging data', 'data': data}); }); эту подписку я делаю по команде с клиента, по другой же или по disconnect отписываюсь: socket.on('disconnect', function() { profiler.unsubscribe(socket.id); });
Как видите, очень гибко и удобно, надеюсь кому-нибудь это поможет в нелегком деле рефакторинга.
Спасибо за внимание!
PS: Для тех, кому не нравится неприватность свойства clients в нашем профайлере, всегда можно( и нужно ) сделать так:
var profiler = function(){ var clients = []; this.add = function(id, next){...} this.del = function(id){...} this.log = function(data){...} }