anchor.diff:                    end
             end,
             [],
  -          LogEntries),
  +          LogEntries3),
       LogStructs.
   
   category_bin(info) -> <<"info">>;
  
positive.code: 
  %% External API
  
  -define(ALERTS_LIMIT, 15).
  
  handle_logs(Req) ->
      reply_json(Req, {struct, [{list, build_logs(Req:parse_qs())}]}).
  
  handle_alerts(Req) ->
      reply_json(Req, {struct, [{limit, ?ALERTS_LIMIT},
                                {settings, {struct, [{updateUri,
                                                      <<"/alerts/settings">>}
                                                     | fetch_alert_settings()]}},
                                {list, build_alerts(Req:parse_qs())}]}).
  
  handle_alerts_settings_post(Req) ->
      PostArgs = Req:parse_post(),
      call_simple_cache(insert,
                        [{alert_settings,
                          lists:map(fun ({K,V}) ->
                                            {list_to_atom(K), list_to_binary(V)}
                                    end,
                                    PostArgs)}]),
      %% TODO: make it more RESTful
      Req:respond({200, [], []}).
  
  build_logs(Params) ->
      MinTStamp = case proplists:get_value("minTimeStamp", Params) of
                       undefined -> 0;
                       V -> list_to_integer(V)
                   end,
      LogEntries = lists:filter(
                     fun(#log_entry{tstamp = TStamp}) ->
                             TStamp > MinTStamp
                     end,
                     ns_log:recent()),
      build_log_structs(LogEntries).
  
  build_log_structs(LogEntries) ->
      LogStructs =
          lists:foldl(
            fun(#log_entry{module = Module,
  
negative.code: category_bin(_)    -> <<"info">>.
  
  build_alerts(Params) ->
      {MinTStamp, Limit} = common_params(Params),
      AlertConfig = get_alert_config(),
      Alerts = proplists:get_value(alerts, AlertConfig, []),
      LogEntries = ns_log:recent(),
      LogEntries2 = lists:filter(
                      fun(#log_entry{module = Module,
                                     code = Code}) ->
                              lists:member(alert_key(Module, Code), Alerts)
                      end,
                      LogEntries),
      build_log_structs(LogEntries2, MinTStamp, Limit).
  
  % The defined alert_key() responses are...
  %
  %  server_down
  %  server_up
  %  server_joined
  %  memory_low
  %  bucket_created
  %  config_changed
  
  is_alert_key("server_down")    -> true;
  is_alert_key("server_up")      -> true;
  is_alert_key("server_joined")  -> true;
  is_alert_key("memory_low")     -> true;
  is_alert_key("bucket_created") -> true;
  is_alert_key("config_changed") -> true;
  is_alert_key(_) -> false.
  
  alert_key(_Module, _Code) -> all.
  
  default_alert_config() ->
      [{email, ""},
       {email_alerts, false},
       {alerts, []}].
  
  get_alert_config() ->
      case ns_config:search(ns_config:get(), alerts) of
          {value, X} -> X;
          false      -> default_alert_config()
      end.
  
  set_alert_config(AlertConfig) ->
      ns_config:set(alerts, AlertConfig).
  
  common_params(Params) ->
      MinTStamp = case proplists:get_value("sinceTime", Params) of
                       undefined -> 0;
                       V -> list_to_integer(V)
                   end,
      Limit = case proplists:get_value("limit", Params) of
                  undefined -> ?DEFAULT_LIMIT;
                  L -> list_to_integer(L)
              end,
      {MinTStamp, Limit}.
  
  -ifdef(EUNIT).
  
  test() ->
      eunit:test(wrap_tests_with_cache_setup({module, ?MODULE}),
  