add log support
This commit is contained in:
parent
9bed8c8622
commit
582b819e9f
@ -246,13 +246,17 @@
|
|||||||
status = 0
|
status = 0
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
%% 设备分类
|
||||||
|
-define(DEVICE_HOST, 1).
|
||||||
|
-define(DEVICE_TERMINAL, 2).
|
||||||
|
|
||||||
%% 操作日志表
|
%% 操作日志表
|
||||||
-record(log, {
|
-record(log, {
|
||||||
log_id :: integer(),
|
log_id :: integer(),
|
||||||
%% 操作名称名称
|
%% 操作名称名称
|
||||||
action_name = <<>>,
|
action_name = <<>>,
|
||||||
%% 设备分类名称
|
%% 设备分类名称
|
||||||
assoc_name = <<>>,
|
device_type :: integer(),
|
||||||
%% 关联ID
|
%% 关联ID
|
||||||
assoc_id :: term(),
|
assoc_id :: term(),
|
||||||
%% 创建时间
|
%% 创建时间
|
||||||
|
|||||||
41
apps/iot/src/http_handler/http_log_handler.erl
Normal file
41
apps/iot/src/http_handler/http_log_handler.erl
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @author licheng5
|
||||||
|
%%% @copyright (C) 2020, <COMPANY>
|
||||||
|
%%% @doc
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 26. 4月 2020 3:36 下午
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(http_log_handler).
|
||||||
|
-author("licheng5").
|
||||||
|
-include("iot.hrl").
|
||||||
|
|
||||||
|
%% API
|
||||||
|
-export([handle_request/4]).
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% helper methods
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
handle_request(_, "/log/list", GetParams, _PostParams) ->
|
||||||
|
Size0 = maps:get(<<"size">>, GetParams, <<"10">>),
|
||||||
|
Size = binary_to_integer(Size0),
|
||||||
|
true = Size > 0,
|
||||||
|
|
||||||
|
case log_model:get_last_logs(Size) of
|
||||||
|
{ok, Logs} ->
|
||||||
|
LogInfos = lists:map(fun log_model:to_map/1, Logs),
|
||||||
|
|
||||||
|
{ok, 200, iot_util:json_data(LogInfos)};
|
||||||
|
{error, Reason} ->
|
||||||
|
lager:warning("[host_handler] get a error: ~p", [Reason]),
|
||||||
|
{ok, 200, iot_util:json_error(-1, <<"database error">>)}
|
||||||
|
end;
|
||||||
|
|
||||||
|
handle_request(_, Path, _, _) ->
|
||||||
|
Path1 = list_to_binary(Path),
|
||||||
|
{ok, 200, iot_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}.
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% helper methods
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
@ -64,7 +64,7 @@ supported_gzip(AcceptEncoding) when is_binary(AcceptEncoding) ->
|
|||||||
parse_body(Req0) ->
|
parse_body(Req0) ->
|
||||||
ContentType = cowboy_req:header(<<"content-type">>, Req0),
|
ContentType = cowboy_req:header(<<"content-type">>, Req0),
|
||||||
case ContentType of
|
case ContentType of
|
||||||
<<"application/json">> ->
|
<<"application/json", _/binary>> ->
|
||||||
{ok, Body, Req1} = read_body(Req0),
|
{ok, Body, Req1} = read_body(Req0),
|
||||||
{ok, catch jiffy:decode(Body, [return_maps]), Req1};
|
{ok, catch jiffy:decode(Body, [return_maps]), Req1};
|
||||||
<<"application/x-www-form-urlencoded">> ->
|
<<"application/x-www-form-urlencoded">> ->
|
||||||
|
|||||||
@ -42,7 +42,10 @@ start_http_server() ->
|
|||||||
Dispatcher = cowboy_router:compile([
|
Dispatcher = cowboy_router:compile([
|
||||||
{'_', [
|
{'_', [
|
||||||
{"/host/[...]", http_protocol, [http_host_handler]},
|
{"/host/[...]", http_protocol, [http_host_handler]},
|
||||||
{"/api/[...]", http_protocol, [http_api_handler]},
|
{"/terminal/[...]", http_protocol, [http_terminal_handler]},
|
||||||
|
{"/scenario/[...]", http_protocol, [http_scenario_handler]},
|
||||||
|
{"/log/[...]", http_protocol, [http_log_handler]},
|
||||||
|
{"/iot/[...]", http_protocol, [http_iot_handler]},
|
||||||
{"/router/[...]", http_protocol, [http_router_handler]}
|
{"/router/[...]", http_protocol, [http_router_handler]}
|
||||||
]}
|
]}
|
||||||
]),
|
]),
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
-include("iot.hrl").
|
-include("iot.hrl").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([insert_hosts/0, insert_services/1, insert_terminals/1, insert_routers/0]).
|
-export([insert_hosts/0, insert_services/1, insert_terminals/1, insert_routers/0, insert_logs/0]).
|
||||||
-export([start_router/1]).
|
-export([start_router/1]).
|
||||||
-export([rsa_encode/1]).
|
-export([rsa_encode/1]).
|
||||||
-export([start_issue/0]).
|
-export([start_issue/0]).
|
||||||
@ -43,6 +43,18 @@ insert_hosts() ->
|
|||||||
host_model:add_host(Host)
|
host_model:add_host(Host)
|
||||||
end, lists:seq(1, 1)).
|
end, lists:seq(1, 1)).
|
||||||
|
|
||||||
|
insert_logs() ->
|
||||||
|
lists:foreach(fun(Id0) ->
|
||||||
|
Log = #log{
|
||||||
|
log_id = Id0,
|
||||||
|
device_type = ?DEVICE_HOST,
|
||||||
|
action_name = <<"主机上线"/utf8>>,
|
||||||
|
assoc_id = <<"1">>,
|
||||||
|
create_ts = Id0 + 123456
|
||||||
|
},
|
||||||
|
log_model:add_log(Log)
|
||||||
|
end, lists:seq(1, 500000)).
|
||||||
|
|
||||||
insert_services(HostId) ->
|
insert_services(HostId) ->
|
||||||
lists:foreach(fun(Id0) ->
|
lists:foreach(fun(Id0) ->
|
||||||
Q0 = queue:new(),
|
Q0 = queue:new(),
|
||||||
|
|||||||
@ -14,10 +14,10 @@
|
|||||||
-define(TAB_NAME, log).
|
-define(TAB_NAME, log).
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([get_logs/1, add_log/1, delete/1, table_size/0]).
|
-export([get_logs/1, add_log/1, delete/1, table_size/0, get_last_logs/1]).
|
||||||
-export([to_map/1]).
|
-export([to_map/1]).
|
||||||
|
|
||||||
%% 获取app信息
|
%% 获取app信息, 该函数的效率较低
|
||||||
-spec get_logs(Limit :: integer()) -> {ok, Logs :: list()} | {error, Reason :: any()}.
|
-spec get_logs(Limit :: integer()) -> {ok, Logs :: list()} | {error, Reason :: any()}.
|
||||||
get_logs(Limit) when is_integer(Limit), Limit > 0 ->
|
get_logs(Limit) when is_integer(Limit), Limit > 0 ->
|
||||||
Fun = fun() ->
|
Fun = fun() ->
|
||||||
@ -36,6 +36,20 @@ get_logs(Limit) when is_integer(Limit), Limit > 0 ->
|
|||||||
{error, Error}
|
{error, Error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% 获取最新的n条记录
|
||||||
|
-spec get_last_logs(N :: integer()) -> {ok, Logs :: [#log{}]} | {error, Reason :: any()}.
|
||||||
|
get_last_logs(N) when N > 0 ->
|
||||||
|
Fun = fun() ->
|
||||||
|
Keys = read_last_keys(N),
|
||||||
|
lists:flatmap(fun(Key) -> mnesia:read(?TAB_NAME, Key, read) end, lists:reverse(Keys))
|
||||||
|
end,
|
||||||
|
case mnesia:transaction(Fun) of
|
||||||
|
{atomic, Logs} when is_list(Logs) ->
|
||||||
|
{ok, Logs};
|
||||||
|
{aborted, Error} ->
|
||||||
|
{error, Error}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec add_log(Log :: #log{}) -> ok | {error, Reason :: binary()}.
|
-spec add_log(Log :: #log{}) -> ok | {error, Reason :: binary()}.
|
||||||
add_log(Log = #log{}) ->
|
add_log(Log = #log{}) ->
|
||||||
case mnesia:transaction(fun() -> mnesia:write(?TAB_NAME, Log, write) end) of
|
case mnesia:transaction(fun() -> mnesia:write(?TAB_NAME, Log, write) end) of
|
||||||
@ -54,6 +68,24 @@ delete(LogId) when is_binary(LogId) ->
|
|||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% 从后向前变量表
|
||||||
|
read_last_keys(N) when N >= 1 ->
|
||||||
|
case mnesia:last(?TAB_NAME) of
|
||||||
|
'$end_of_table' ->
|
||||||
|
[];
|
||||||
|
LastKey ->
|
||||||
|
read_last_keys0(N - 1, LastKey, [LastKey])
|
||||||
|
end.
|
||||||
|
read_last_keys0(0, _, Keys) ->
|
||||||
|
Keys;
|
||||||
|
read_last_keys0(N, Key, Keys) ->
|
||||||
|
case mnesia:prev(?TAB_NAME, Key) of
|
||||||
|
'$end_of_table' ->
|
||||||
|
Keys;
|
||||||
|
PrevKey ->
|
||||||
|
read_last_keys0(N - 1, PrevKey, [PrevKey|Keys])
|
||||||
|
end.
|
||||||
|
|
||||||
%% 获取app表的数据大小
|
%% 获取app表的数据大小
|
||||||
table_size() ->
|
table_size() ->
|
||||||
mnesia:table_info(?TAB_NAME, size).
|
mnesia:table_info(?TAB_NAME, size).
|
||||||
@ -67,9 +99,28 @@ sort(Logs) when is_list(Logs) ->
|
|||||||
lists:sort(fun(#log{create_ts = Ts0}, #log{create_ts = Ts1}) -> Ts0 > Ts1 end, Logs).
|
lists:sort(fun(#log{create_ts = Ts0}, #log{create_ts = Ts1}) -> Ts0 > Ts1 end, Logs).
|
||||||
|
|
||||||
%% 将数据转换成hash
|
%% 将数据转换成hash
|
||||||
to_map(#log{log_id = LogId, action_name = ActionName, assoc_name = AssocName, assoc_id = AssocId, create_ts = CreateTs}) ->
|
to_map(#log{log_id = LogId, action_name = ActionName, device_type = DeviceType, assoc_id = AssocId, create_ts = CreateTs}) ->
|
||||||
|
DeviceInfo = case DeviceType of
|
||||||
|
?DEVICE_HOST ->
|
||||||
|
case host_model:get_host(AssocId) of
|
||||||
|
{ok, Host} ->
|
||||||
|
host_model:to_map(Host);
|
||||||
|
_ ->
|
||||||
|
#{}
|
||||||
|
end;
|
||||||
|
?DEVICE_TERMINAL ->
|
||||||
|
case terminal_model:get_terminal(AssocId) of
|
||||||
|
{ok, Terminal} ->
|
||||||
|
terminal_model:to_map(Terminal);
|
||||||
|
_ ->
|
||||||
|
#{}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
#{
|
#{
|
||||||
<<"log_id">> => LogId,
|
<<"log_id">> => LogId,
|
||||||
<<"action_name">> => ActionName,
|
<<"action_name">> => ActionName,
|
||||||
|
<<"device_type">> => DeviceType,
|
||||||
|
<<"device_info">> => DeviceInfo,
|
||||||
<<"create_ts">> => CreateTs
|
<<"create_ts">> => CreateTs
|
||||||
}.
|
}.
|
||||||
Loading…
x
Reference in New Issue
Block a user