Add src/hk_event.erl
Browse files- src/hk_event.erl +73 -0
src/hk_event.erl
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
%%%-------------------------------------------------------------------
|
| 2 |
+
%%% @doc HK-VIS :: Event schema.
|
| 3 |
+
%%%
|
| 4 |
+
%%% Implements the `Event' entity from the data model and the
|
| 5 |
+
%%% append-oriented event model described in the architecture:
|
| 6 |
+
%%% every observable action in the system (agent, browser, search,
|
| 7 |
+
%%% messaging, system) is represented as one immutable `#hk_event{}'
|
| 8 |
+
%%% record with a stable id, a timestamp, a dotted category
|
| 9 |
+
%%% (`agent.created', `browser.navigation.completed', ...), a
|
| 10 |
+
%%% subject (the entity the event is about), and an opaque-to-this-
|
| 11 |
+
%%% module `data' payload map.
|
| 12 |
+
%%%
|
| 13 |
+
%%% This module never inspects `data' -- it only assigns identity
|
| 14 |
+
%%% and timestamp and hands the event to `hk_event_bus'. This keeps
|
| 15 |
+
%%% the event envelope schema decoupled from what any given
|
| 16 |
+
%%% subsystem chooses to report.
|
| 17 |
+
%%% @end
|
| 18 |
+
%%%-------------------------------------------------------------------
|
| 19 |
+
-module(hk_event).
|
| 20 |
+
|
| 21 |
+
-export([new/3, new/4, to_map/1]).
|
| 22 |
+
|
| 23 |
+
-export_type([t/0, category/0]).
|
| 24 |
+
|
| 25 |
+
%% Dotted event category, e.g. <<"agent.action.completed">>.
|
| 26 |
+
-type category() :: binary().
|
| 27 |
+
|
| 28 |
+
-record(hk_event, {
|
| 29 |
+
event_id :: binary(),
|
| 30 |
+
category :: category(),
|
| 31 |
+
%% {Type, Id} identifies the entity the event is about, e.g.
|
| 32 |
+
%% {agent, <<"agent_...">>} or {browser_session, <<"sess_...">>}.
|
| 33 |
+
subject :: {atom(), binary()} | undefined,
|
| 34 |
+
%% correlation id: links an event back to the operation that
|
| 35 |
+
%% caused it, when one exists (see hk_schema:operation()).
|
| 36 |
+
operation_id :: binary() | undefined,
|
| 37 |
+
data :: map(),
|
| 38 |
+
emitted_at_ms :: integer()
|
| 39 |
+
}).
|
| 40 |
+
|
| 41 |
+
-opaque t() :: #hk_event{}.
|
| 42 |
+
|
| 43 |
+
-spec new(category(), {atom(), binary()} | undefined, map()) -> t().
|
| 44 |
+
new(Category, Subject, Data) ->
|
| 45 |
+
new(Category, Subject, Data, undefined).
|
| 46 |
+
|
| 47 |
+
-spec new(category(), {atom(), binary()} | undefined, map(), binary() | undefined) -> t().
|
| 48 |
+
new(Category, Subject, Data, OperationId) when is_binary(Category), is_map(Data) ->
|
| 49 |
+
#hk_event{
|
| 50 |
+
event_id = hk_id:new(<<"evt">>),
|
| 51 |
+
category = Category,
|
| 52 |
+
subject = Subject,
|
| 53 |
+
operation_id = OperationId,
|
| 54 |
+
data = Data,
|
| 55 |
+
emitted_at_ms = hk_id:timestamp_ms()
|
| 56 |
+
}.
|
| 57 |
+
|
| 58 |
+
%% @doc Render for JSON transport / the audit log. This is the only
|
| 59 |
+
%% place the wire representation of an event is defined.
|
| 60 |
+
-spec to_map(t()) -> map().
|
| 61 |
+
to_map(#hk_event{event_id = Id, category = Cat, subject = Subj,
|
| 62 |
+
operation_id = OpId, data = Data, emitted_at_ms = Ts}) ->
|
| 63 |
+
#{
|
| 64 |
+
event_id => Id,
|
| 65 |
+
category => Cat,
|
| 66 |
+
subject => case Subj of
|
| 67 |
+
{Type, SubjId} -> #{type => Type, id => SubjId};
|
| 68 |
+
undefined -> null
|
| 69 |
+
end,
|
| 70 |
+
operation_id => case OpId of undefined -> null; _ -> OpId end,
|
| 71 |
+
data => Data,
|
| 72 |
+
emitted_at_ms => Ts
|
| 73 |
+
}.
|