Состояние в процессе менеджера событий OTP (не обработчик!)
Может ли процесс диспетчера событий OTP (например, регистратор) иметь свое собственное состояние (например, уровень ведения журнала) и фильтровать / преобразовывать события на его основе?
3 ответа
У меня также есть необходимость поместить некоторое состояние в сам gen_event, и моя лучшая идея на данный момент - использовать словарь процессов (get/put). Обработчики вызываются в контексте процесса gen_event, поэтому один и тот же словарь процесса будет доступен для всех вызовов обработчиков.
Да, словари процессов - это зло, но в этом случае они кажутся менее злыми, чем альтернативы (таблица, сервер состояний).
Реализация gen_event, содержащаяся в OTP, не предоставляет средства для добавления состояния. Вы можете расширить реализацию для достижения этой цели и использовать свою реализацию вместо gen_event. Однако я бы посоветовал против этого.
Тип состояния, которое вы хотите добавить в диспетчер событий, действительно принадлежит обработчику событий по нескольким причинам:
Возможно, вы захотите использовать разные уровни в разных обработчиках, например, отображать только ошибки на консоли, но записывать все на диск.
Если уровень события будет изменен в обработчиках событий менеджера в зависимости от получения всех неотфильтрованных событий, они могут перестать функционировать (события имеют больше применений, чем просто ведение журнала). Это может привести к трудностям при отладке.
Если вам нужен менеджер событий для нескольких обработчиков, которые все получают только отфильтрованные события, вы можете легко добиться этого, имея два менеджера: один для нефильтрованных сообщений и один, например, для сообщений с уровнем фильтрации. Затем установите обработчик на неотфильтрованный, отфильтруйте его по уровню (легко) и передайте отфильтрованные события другому менеджеру. Все обработчики, которые хотят получать только отфильтрованные сообщения, могут быть зарегистрированы во втором менеджере.
Обработчики могут иметь свое собственное состояние, которое передается при каждом обратном вызове, например:
Module:handle_event(Event, State) -> Result
Фильтрация может выглядеть следующим образом (при условии, например, {level N, Content}
События):
handle_event({level, Lvl, Content}, State#state{max_level=Max}) when Lvl >= Max ->
gen_event:notify(filtered_man, Content);
Состояние может быть изменено либо специальными событиями, либо gen_event:call\3,4
(предпочтительно) или сообщениями, обработанными handle_info.
Для получения дополнительной информации см. Gen_Event Behavior и gen_event(3)
Когда ты start_link
gen_event
процесс - то, что вы всегда должны делать через супервизора - вы можете просто указать имя для нового процесса, если вам нужно / хотите, чтобы он был зарегистрирован. Насколько я вижу, нет никакого способа инициировать state
какой-то с использованием этого поведения.
Конечно, вы можете написать свое собственное поведение, на вершине gen_event
или простой gen_server
,
В качестве альтернативы вы можете использовать отдельный gen_event
процесс для каждого уровня отладки. Или вы можете просто отфильтровать сообщения в обработчиках.