| 1 |  | %%% eturnal STUN/TURN server module. | 
| 2 |  | %%% | 
| 3 |  | %%% Copyright (c) 2020 Marc Schink <dev@zapb.de>. | 
| 4 |  | %%% Copyright (c) 2020 ProcessOne, SARL. | 
| 5 |  | %%% All rights reserved. | 
| 6 |  | %%% | 
| 7 |  | %%% Licensed under the Apache License, Version 2.0 (the "License"); | 
| 8 |  | %%% you may not use this file except in compliance with the License. | 
| 9 |  | %%% You may obtain a copy of the License at | 
| 10 |  | %%% | 
| 11 |  | %%%     http://www.apache.org/licenses/LICENSE-2.0 | 
| 12 |  | %%% | 
| 13 |  | %%% Unless required by applicable law or agreed to in writing, software | 
| 14 |  | %%% distributed under the License is distributed on an "AS IS" BASIS, | 
| 15 |  | %%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 16 |  | %%% See the License for the specific language governing permissions and | 
| 17 |  | %%% limitations under the License. | 
| 18 |  |  | 
| 19 |  | %%% This module logs STUN/TURN events with some metadata into an InfluxDB | 
| 20 |  | %%% database. | 
| 21 |  |  | 
| 22 |  | -module(mod_stats_influx). | 
| 23 |  | -behaviour(eturnal_module). | 
| 24 |  | -export([start/0, | 
| 25 |  |          stop/0, | 
| 26 |  |          handle_event/2, | 
| 27 |  |          options/0]). | 
| 28 |  | -import(yval, [either/2, ip/0, non_empty/1, port/0, string/0]). | 
| 29 |  |  | 
| 30 |  | -include_lib("kernel/include/logger.hrl"). | 
| 31 |  | -define(INFLUX_POOL, stats_influx_pool). | 
| 32 |  |  | 
| 33 |  | %% API. | 
| 34 |  |  | 
| 35 |  | -spec start() -> {ok, eturnal_module:events()}. | 
| 36 |  | start() -> | 
| 37 | 3 |     ?LOG_DEBUG("Starting ~s", [?MODULE]), | 
| 38 | 3 |     ok = eturnal_module:ensure_deps(?MODULE, [influx_udp]), | 
| 39 | 3 |     Host = eturnal_module:get_opt(?MODULE, host), | 
| 40 | 3 |     Port = eturnal_module:get_opt(?MODULE, port), | 
| 41 | 3 |     Events = [turn_session_stop, stun_query], | 
| 42 | 3 |     case influx_udp:start_pool(?INFLUX_POOL, #{host => Host, | 
| 43 |  |                                                port => Port, | 
| 44 |  |                                                pool_size => 1}) of | 
| 45 |  |         {ok, _} -> | 
| 46 | 1 |             {ok, Events}; | 
| 47 |  |         {error, {already_started, _}} -> | 
| 48 | 2 |             {ok, Events}; | 
| 49 |  |         {error, Reason} -> | 
| 50 | :-( |             exit(Reason) | 
| 51 |  |     end. | 
| 52 |  |  | 
| 53 |  | -spec handle_event(eturnal_module:event(), eturnal_module:info()) -> ok. | 
| 54 |  | handle_event(stun_query, Info) -> | 
| 55 | 5 |     on_stun_query(Info); | 
| 56 |  | handle_event(turn_session_stop, Info) -> | 
| 57 | 2 |     on_turn_session_stop(Info). | 
| 58 |  |  | 
| 59 |  | -spec stop() -> ok. | 
| 60 |  | stop() -> | 
| 61 | 3 |     ?LOG_DEBUG("Stopping ~s", [?MODULE]), | 
| 62 | 3 |     ok. | 
| 63 |  |  | 
| 64 |  | -spec options() -> eturnal_module:options(). | 
| 65 |  | options() -> | 
| 66 | 3 |     {#{host => either(ip(), non_empty(string())), | 
| 67 |  |        port => port()}, | 
| 68 |  |      [{defaults, | 
| 69 |  |        #{host => "localhost", | 
| 70 |  |          port => 8089}}]}. | 
| 71 |  |  | 
| 72 |  | %% Internal functions. | 
| 73 |  |  | 
| 74 |  | -spec on_stun_query(eturnal_module:info()) -> ok. | 
| 75 |  | on_stun_query(#{transport := Transport}) -> | 
| 76 | 5 |     ?LOG_DEBUG("Writing STUN query event to InfluxDB"), | 
| 77 | 5 |     Points = [{type, <<"stun">>}, | 
| 78 |  |               {transport, string:lowercase(Transport)}], | 
| 79 | 5 |     ok = influx_udp:write_to(?INFLUX_POOL, <<"events">>, Points). | 
| 80 |  |  | 
| 81 |  | -spec on_turn_session_stop(eturnal_module:info()) -> ok. | 
| 82 |  | on_turn_session_stop(#{id := ID, | 
| 83 |  |                        transport := Transport, | 
| 84 |  |                        sent_bytes := Sent, | 
| 85 |  |                        rcvd_bytes := Rcvd, | 
| 86 |  |                        duration := Duration0}) -> | 
| 87 | 2 |     ?LOG_DEBUG("Writing stats of TURN session ~s to InfluxDB", [ID]), | 
| 88 | 2 |     Duration = erlang:convert_time_unit(Duration0, native, microsecond), | 
| 89 | 2 |     Points = [{type, <<"turn">>}, | 
| 90 |  |               {transport, string:lowercase(Transport)}, | 
| 91 |  |               {duration, Duration}, | 
| 92 |  |               {sent_bytes, Sent}, | 
| 93 |  |               {rcvd_bytes, Rcvd}], | 
| 94 | 2 |     ok = influx_udp:write_to(?INFLUX_POOL, <<"events">>, Points). |