OTP 事件管理器进程(例如记录器)是否可以拥有自己的某种状态(例如日志记录级别)并基于它过滤/转换事件?
3 回答
OTP 中包含的 gen_event 实现不提供添加状态的方法。您可以扩展实现以实现此目的并使用您的实现而不是 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 行为和gen_event(3)
我还需要将一些状态放入 gen_event 本身,我目前最好的想法是使用进程字典(get/put)。处理程序是在 gen_event 进程的上下文中调用的,因此所有处理程序调用都将存在同一个进程字典。
是的,进程字典是邪恶的,但在这种情况下,它们似乎不如替代品(ets 表、状态服务器)那么邪恶。
当您处理流程时(您应该始终通过主管执行start_link
的gen_event
操作),如果您需要/希望注册新流程,您只需指定新流程的名称即可。据我所知,没有办法state
使用这种行为来启动某种类型的行为。
当然,您可以在 agen_event
或简单的gen_server
.
作为替代方案,您可以gen_event
为每个调试级别使用单独的进程。或者您可以只过滤处理程序中的消息。