aboutsummaryrefslogtreecommitdiffstats
path: root/lib/otp_mibs/src/otp_mib.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/otp_mibs/src/otp_mib.erl')
-rw-r--r--lib/otp_mibs/src/otp_mib.erl198
1 files changed, 198 insertions, 0 deletions
diff --git a/lib/otp_mibs/src/otp_mib.erl b/lib/otp_mibs/src/otp_mib.erl
new file mode 100644
index 0000000000..e8b0e51b91
--- /dev/null
+++ b/lib/otp_mibs/src/otp_mib.erl
@@ -0,0 +1,198 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(otp_mib).
+%%%-----------------------------------------------------------------
+%%% Description: This module implements the OTP-MIB.
+%%% The tables are implemented as shadow tables with the module
+%%% snmp_shadow_table.
+%%%-----------------------------------------------------------------
+
+%% API
+-export([load/1, unload/1]).
+
+%% SNMP instrumentation
+-export([erl_node_table/1, erl_node_table/3, appl_table/1, appl_table/3]).
+
+%% SNMP shadow functions
+-export([update_erl_node_table/0, update_appl_table/0]).
+
+%% Exported for internal use via rpc
+-export([get_erl_node/1, get_appls/1]).
+
+%% Shadow tables
+-record(erlNodeTable,
+ {erlNodeId, erlNodeName, erlNodeMachine, erlNodeVersion,
+ erlNodeRunQueue,
+ erlNodeRunTime, erlNodeWallClock, erlNodeReductions,
+ erlNodeProcesses, erlNodeInBytes, erlNodeOutBytes}).
+
+-record(applTable, {key = '_', applName = '_', applDescr = '_',
+ applVsn = '_'}).
+
+%% Shadow argument macros
+-define(erlNodeShadowArgs,
+ {erlNodeTable, integer, record_info(fields, erlNodeTable), 5000,
+ {otp_mib, update_erl_node_table}}).
+
+-define(applShadowArgs,
+ {applTable, {integer, integer}, record_info(fields, applTable),
+ 5000, {otp_mib, update_appl_table}}).
+
+%% Misc
+-record(erlNodeAlloc, {nodeName, nodeId}).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+%%-------------------------------------------------------------------------
+%% load(Agent) -> ok | {error, Reason}
+%% Agent - pid() | atom()
+%% Reason - term()
+%% Description: Loads the OTP-MIB
+%%-------------------------------------------------------------------------
+load(Agent) ->
+ MibDir = code:priv_dir(otp_mibs) ++ "/mibs",
+ snmpa:load_mibs(Agent, [MibDir ++ "/OTP-MIB"]).
+
+%%-------------------------------------------------------------------------
+%% unload(Agent) -> ok | {error, Reason}
+%% Agent - pid() | atom()
+%% Reason - term()
+%% Description: Loads the OTP-MIB
+%%-------------------------------------------------------------------------
+unload(Agent) ->
+ snmpa:unload_mibs(Agent, ["OTP-MIB"]).
+
+
+%%%=========================================================================
+%%% SNMP instrumentation
+%%%=========================================================================
+erl_node_table(new) ->
+ Tab = erlNodeAlloc,
+ Storage = ram_copies,
+ case lists:member(Tab, mnesia:system_info(tables)) of
+ true ->
+ case mnesia:table_info(Tab, storage_type) of
+ unknown ->
+ {atomic, ok} = mnesia:add_table_copy(Tab, node(), Storage);
+ Storage ->
+ catch delete_all(Tab)
+ end;
+ false ->
+ Nodes = [node()],
+ Props = [{type, set},
+ {attributes, record_info(fields, erlNodeAlloc)},
+ {local_content, true},
+ {Storage, Nodes}],
+ {atomic, ok} = mnesia:create_table(Tab, Props)
+ end,
+ ok = mnesia:dirty_write({erlNodeAlloc, next_index, 1}),
+ update_node_alloc([node() | nodes()]),
+ snmp_shadow_table:table_func(new, ?erlNodeShadowArgs).
+
+erl_node_table(Op, RowIndex, Cols) ->
+ snmp_shadow_table:table_func(Op, RowIndex, Cols, ?erlNodeShadowArgs).
+
+
+appl_table(Op) ->
+ snmp_shadow_table:table_func(Op, ?applShadowArgs).
+appl_table(Op, RowIndex, Cols) ->
+ snmp_shadow_table:table_func(Op, RowIndex, Cols, ?applShadowArgs).
+
+
+%%%=========================================================================
+%%% SNMP shadow functions
+%%%=========================================================================
+update_erl_node_table() ->
+ delete_all(erlNodeTable),
+ Nodes = [node() | nodes()],
+ update_node_alloc(Nodes),
+ lists:foreach(
+ fun(Node) ->
+ [{_,_,Idx}] = mnesia:dirty_read({erlNodeAlloc, Node}),
+ ErlNode = rpc:call(Node, otp_mib, get_erl_node, [Idx]),
+ ok = mnesia:dirty_write(ErlNode)
+ end, Nodes).
+
+update_appl_table() ->
+ delete_all(applTable),
+ Nodes = [node() | nodes()],
+ update_node_alloc(Nodes),
+ lists:foreach(
+ fun(Node) ->
+ [{_,_,Idx}] = mnesia:dirty_read({erlNodeAlloc, Node}),
+ Appls = rpc:call(Node, otp_mib, get_appls, [Idx]),
+ lists:foreach(fun(Appl) ->
+ ok = mnesia:dirty_write(Appl)
+ end, Appls)
+ end, Nodes).
+
+%%%========================================================================
+%%% Exported for internal use via rpc
+%%%========================================================================
+get_erl_node(Id) ->
+ IO = erlang:statistics(io),
+ #erlNodeTable{erlNodeId = Id,
+ erlNodeName = atom_to_list(node()),
+ erlNodeVersion = erlang:system_info(version),
+ erlNodeMachine = erlang:system_info(machine),
+ erlNodeRunQueue = erlang:statistics(run_queue),
+ erlNodeRunTime = element(1, erlang:statistics(runtime)),
+ erlNodeWallClock =
+ element(1, erlang:statistics(wall_clock)),
+ erlNodeReductions =
+ element(1, erlang:statistics(reductions)),
+ erlNodeProcesses = length(processes()),
+ erlNodeInBytes = element(2, element(1, IO)),
+ erlNodeOutBytes = element(2, element(2, IO))}.
+
+get_appls(NodeId) ->
+ element(1,
+ lists:mapfoldl(
+ fun({ApplName, ApplDescr, ApplVsn}, ApplId) ->
+ {#applTable{key = {NodeId, ApplId},
+ applName = atom_to_list(ApplName),
+ applDescr = ApplDescr,
+ applVsn = ApplVsn},
+ ApplId + 1}
+ end, 1, application:which_applications())).
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+update_node_alloc([Node | T]) ->
+ case mnesia:dirty_read({erlNodeAlloc, Node}) of
+ [] ->
+ [{_, _, Idx}] = mnesia:dirty_read({erlNodeAlloc, next_index}),
+ ok = mnesia:dirty_write(#erlNodeAlloc{nodeName = Node,
+ nodeId = Idx}),
+ ok = mnesia:dirty_write({erlNodeAlloc, next_index, Idx + 1});
+ _ ->
+ ok
+ end,
+ update_node_alloc(T);
+update_node_alloc([]) -> ok.
+
+delete_all(Name) -> delete_all(mnesia:dirty_first(Name), Name).
+delete_all('$end_of_table', _Name) -> done;
+delete_all(Key, Name) ->
+ Next = mnesia:dirty_next(Name, Key),
+ ok = mnesia:dirty_delete({Name, Key}),
+ delete_all(Next, Name).