Статьи

Сделайте свою жизнь проще, войдя в ВСЕ как JSON

История инженера.

Вот анекдот. Я уверен, что у некоторых из вас был подобный опыт.

  1. Алекс, инженер, регистрирует все виды событий. Поскольку он является основным потребителем журнала, формат оптимизирован для удобства чтения. Один канонический пример — журналы Apache:

    10.0.1.22 — — [15 / Oct / 2010: 11: 46: 46 -0700] «GET /favicon.ico HTTP / 1.1» 404… 10.0.1.22 — — [15 / Oct / 2010: 11: 46: 58 — 0700] «GET / HTTP / 1.1» 200…

    Это выглядит великолепно. Отметка времени, URL, код состояния HTTP … каждая строка дает Алексу много информации для работы, если у службы возникают проблемы.

  2. Боб, бизнес-аналитик, спрашивает Алекса о количестве ежедневных уникальных пользователей. Алекс пишет парсер для журнала Apache и crontabs скрипт. Он также создает небольшой веб-интерфейс, чтобы его коллега мог запрашивать проанализированные данные самостоятельно. Боб считает интерфейс очень полезным.

  3. Боб возвращается через несколько недель и жалуется, что веб-интерфейс не работает. Алекс почесывает голову и просматривает журналы, только чтобы понять, что кто-то добавил дополнительное поле в каждую строку, нарушая его собственный анализатор. Он вносит изменения и говорит Бобу, что все снова хорошо. Вместо того, чтобы писать новую функцию, Алекс должен вернуться и заполнить недостающие данные.

  4. Каждые 3 недели или около того повторите шаг 3.

Что с этим не так?

Урок этой истории состоит из двух частей: (1) журналы предназначены не только для чтения людьми, а (2) журналы изменяются.

(1) Журналы не только для людей. Как указывает Пол Керна , основной потребитель бревен переходит от людей к компьютерам. Это означает, что форматы журналов должны иметь четко определенную структуру, которая может быть проанализирована легко и надежно.

(2) Журналы меняются. Если журналы никогда не менялись, написание пользовательского парсера может быть не слишком страшным. Инженер напишет это один раз и будет сделано. Но на самом деле логи меняются. Каждый раз, когда вы добавляете функцию, вы начинаете регистрировать больше данных, и когда вы добавляете больше данных, формат в стиле printf неизбежно изменяется. Это подразумевает, что пользовательский анализатор должен постоянно обновляться, что требует значительного времени на разработку.

Введите JSON!

Вот предложение: начать регистрировать ваши данные как JSON.

У JSON есть несколько преимуществ перед другими «структурами».

  1. Широко принят. Большинство инженеров знают, что такое JSON, и есть библиотека JSON для всех мыслимых языков. Это означает, что для анализа журналов требуется немного больше времени.

  2. Удобочитаемый. Читаемость имеет значение, потому что инженеры должны прыгать и читать журналы, если есть проблема. JSON основан на тексте (в отличие от двоичного), а его формат представляет собой подмножество литералов объектов JavaScript (с которыми знакомо большинство инженеров). На самом деле, правильно отформатированный JSON легче читать, чем журналы, отформатированные специальными способами.

Пример ведения журнала на основе JSON: Fluentd

Мы уже говорили о Fluentd в этом блоге , поэтому я не буду беспокоить вас деталями. Это демон регистрации, который может общаться с различными сервисами (например: MongoDB , Scribe и т. Д.)

Одной из ключевых особенностей Fluentd является то, что все зарегистрировано как JSON . Вот небольшой фрагмент кода, который записывает данные в Fluentd из Ruby.

require ‘fluent-logger’
# some code in between
log = Fluent::Logger::FluentLogger.new(nil, :host => ‘localhost’, :port=>24224)
log.post(‘myapp.access’, {“user-agent” => user_agent})

Теперь предположим, что вы хотите начать регистрацию URL-адреса реферера в дополнение к пользовательскому агенту. Вам просто нужно обновить хэш Ruby, соответствующий JSON.

require ‘fluent-logger’
# some code in between
log = Fluent::Logger::FluentLogger.new(nil, :host => ‘localhost’, :port=>24224)
log.post(‘myapp.access’, {“user-agent” => user_agent, ”referrer” => referrer_url}) # Added a field!

Это единственное изменение, которое вам нужно сделать. Все существующие сценарии работают как прежде, так как все, что мы сделали, это добавили новое поле в существующий JSON.

Напротив, представьте, что вы записываете одни и те же данные в формате, вдохновленном printf. Ваш код изначально выглядит так:

log = CustomLogger.new
#some code in between
log.post(“web.access”, “user-agent: #{user_agent} blah blah”)

Когда вы решите зарегистрировать URL реферера, вы обновите его до:

log = CustomLogger.new
#some code in between
log.post(“web.access”, “user-agent: #{user_agent} blah blah referrer: #{referrer_url}”)

Теперь, скорее всего, ваш старый парсер сломан, и вы должны пойти и обновить свое регулярное выражение и еще много чего.

Мы склонны к Fluentd, потому что мы написали это сами. Но независимо от того, какое программное обеспечение / фреймворк вы выберете для регистрации, вы должны сразу начать регистрировать все как JSON.