1%% Copyright (c) 2011-2013 Basho Technologies, Inc. All Rights Reserved. 2%% 3%% This file is provided to you under the Apache License, 4%% Version 2.0 (the "License"); you may not use this file 5%% except in compliance with the License. You may obtain 6%% a copy of the License at 7%% 8%% http://www.apache.org/licenses/LICENSE-2.0 9%% 10%% Unless required by applicable law or agreed to in writing, 11%% software distributed under the License is distributed on an 12%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13%% KIND, either express or implied. See the License for the 14%% specific language governing permissions and limitations 15%% under the License. 16 17%% @doc A simple gen_event backend used to monitor mailbox size and 18%% switch log messages between synchronous and asynchronous modes. 19%% A gen_event handler is used because a process getting its own mailbox 20%% size doesn't involve getting a lock, and gen_event handlers run in their 21%% parent's process. 22 23-module(lager_backend_throttle). 24 25-include("lager.hrl"). 26 27-behaviour(gen_event). 28 29-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, 30 code_change/3]). 31 32%% 33%% Allow test code to verify that we're doing the needful. 34-ifdef(TEST). 35-define(ETS_TABLE, async_threshold_test). 36-define(TOGGLE_SYNC(), test_increment(sync_toggled)). 37-define(TOGGLE_ASYNC(), test_increment(async_toggled)). 38-else. 39-define(TOGGLE_SYNC(), true). 40-define(TOGGLE_ASYNC(), true). 41-endif. 42 43-record(state, { 44 sink :: atom(), 45 hwm :: non_neg_integer(), 46 window_min :: non_neg_integer(), 47 async = true :: boolean() 48 }). 49 50init([{sink, Sink}, Hwm, Window]) -> 51 lager_config:set({Sink, async}, true), 52 {ok, #state{sink=Sink, hwm=Hwm, window_min=Hwm - Window}}. 53 54 55handle_call(get_loglevel, State) -> 56 {ok, {mask, ?LOG_NONE}, State}; 57handle_call({set_loglevel, _Level}, State) -> 58 {ok, ok, State}; 59handle_call(_Request, State) -> 60 {ok, ok, State}. 61 62handle_event({log, _Message},State) -> 63 {message_queue_len, Len} = erlang:process_info(self(), message_queue_len), 64 case {Len > State#state.hwm, Len < State#state.window_min, State#state.async} of 65 {true, _, true} -> 66 %% need to flip to sync mode 67 ?TOGGLE_SYNC(), 68 lager_config:set({State#state.sink, async}, false), 69 {ok, State#state{async=false}}; 70 {_, true, false} -> 71 %% need to flip to async mode 72 ?TOGGLE_ASYNC(), 73 lager_config:set({State#state.sink, async}, true), 74 {ok, State#state{async=true}}; 75 _ -> 76 %% nothing needs to change 77 {ok, State} 78 end; 79handle_event(_Event, State) -> 80 {ok, State}. 81 82handle_info(_Info, State) -> 83 {ok, State}. 84 85%% @private 86terminate(_Reason, _State) -> 87 ok. 88 89%% @private 90code_change(_OldVsn, State, _Extra) -> 91 {ok, State}. 92 93-ifdef(TEST). 94test_get(Key) -> 95 get_default(ets:lookup(?ETS_TABLE, Key)). 96 97test_increment(Key) -> 98 ets:insert(?ETS_TABLE, 99 {Key, test_get(Key) + 1}). 100 101get_default([]) -> 102 0; 103get_default([{_Key, Value}]) -> 104 Value. 105-endif. 106