%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% -module(httpd_log). -include("httpd.hrl"). -export([access_entry/8, error_entry/5, error_report_entry/5, security_entry/5]). %%%========================================================================= %%% Internal Application API %%%========================================================================= -spec access_entry(Log :: term(), % Id of the log NoLog :: term(), % What to return when no log is found Info :: #mod{}, RFC931 :: string(), AuthUser :: string(), Date :: string(), StatusCode :: pos_integer(), Size :: 0 | pos_integer() | string()) -> {Log :: atom() | pid(), Entry :: string()} | term() . %% Somethime the size in the form of the content_length is put here, which %% is actually in the form of a string %% So it can either be the size as an integer, the size as a string %% or, worst case scenario, bytes. access_entry(Log, NoLog, Info, RFC931, AuthUser, Date, StatusCode, SizeStrOrBytes) when is_list(SizeStrOrBytes) -> Size = case (catch list_to_integer(SizeStrOrBytes)) of I when is_integer(I) -> %% This is from using the content_length (which is a string) I; _ -> %% This is better than nothing httpd_util:flatlength(SizeStrOrBytes) end, access_entry(Log, NoLog, Info, RFC931, AuthUser, Date, StatusCode, Size); access_entry(Log, NoLog, #mod{config_db = ConfigDB, init_data = #init_data{peername = {_, RemoteHost}}, request_line = RequestLine, parsed_header = Headers}, RFC931, AuthUser, Date, StatusCode, Size) -> MakeEntry = fun() -> do_access_entry(ConfigDB, Headers, RequestLine, RemoteHost, RFC931, AuthUser, Date, StatusCode, Size) end, log_entry(Log, NoLog, ConfigDB, MakeEntry). -spec error_entry(Log :: term(), % Id of the log NoLog :: term(), % What to return when no log is found Info :: #mod{}, Date :: string(), Reason :: term()) -> {Log :: atom() | pid(), Entry :: string()} | term(). error_entry(Log, NoLog, #mod{config_db = ConfigDB, init_data = #init_data{peername = {_, RemoteHost}}, request_uri = URI}, Date, Reason) -> MakeEntry = fun() -> do_error_entry(ConfigDB, RemoteHost, URI, Date, Reason) end, log_entry(Log, NoLog, ConfigDB, MakeEntry). -spec error_report_entry(Log :: term(), NoLog :: term(), ConfigDB :: term(), Date :: string(), ErrroStr :: string()) -> {Log :: atom() | pid(), Entry :: string()} | term(). error_report_entry(Log, NoLog, ConfigDb, Date, ErrorStr) -> MakeEntry = fun() -> io_lib:format("[~s], ~s~n", [Date, ErrorStr]) end, log_entry(Log, NoLog, ConfigDb, MakeEntry). -spec security_entry(Log :: term(), NoLog :: term(), ConfigDB :: term(), Date :: string(), Reason :: term()) -> {Log :: atom() | pid(), Entry :: string()} | term(). security_entry(Log, NoLog, #mod{config_db = ConfigDB}, Date, Reason) -> MakeEntry = fun() -> io_lib:format("[~s] ~s~n", [Date, Reason]) end, log_entry(Log, NoLog, ConfigDB, MakeEntry). log_entry(Log, NoLog, ConfigDb, MakeEntry) when is_function(MakeEntry) -> case httpd_util:lookup(ConfigDb, Log) of undefined -> NoLog; LogRef -> {LogRef, MakeEntry()} end. %%%======================================================================== %%% Internal functions %%%======================================================================== do_access_entry(ConfigDB, Headers, RequestLine, RemoteHost, RFC931, AuthUser, Date, StatusCode, Size) -> case httpd_util:lookup(ConfigDB, log_format, common) of common -> lists:flatten(io_lib:format("~s ~s ~s [~s] \"~s\" ~w ~w~n", [RemoteHost, RFC931, AuthUser, Date, RequestLine, StatusCode, Size])); combined -> Referer = proplists:get_value("referer", Headers, "-"), UserAgent = proplists:get_value("user-agent", Headers, "-"), io_lib:format("~s ~s ~s [~s] \"~s\" ~w ~w ~s ~s~n", [RemoteHost, RFC931, AuthUser, Date, RequestLine, StatusCode, Size, Referer, UserAgent]) end. do_error_entry(ConfigDB, RemoteHost, undefined, Date, Reason) -> case httpd_util:lookup(ConfigDB, error_log_format, pretty) of pretty -> io_lib:format("[~s] server crash for ~s, reason: ~n~p~n~n", [Date, RemoteHost, Reason]); compact -> io_lib:format("[~s] server crash for ~s, reason: ~w~n", [Date, RemoteHost, Reason]) end; do_error_entry(ConfigDB, RemoteHost, URI, Date, Reason) -> case httpd_util:lookup(ConfigDB, error_log_format, pretty) of pretty -> io_lib:format("[~s] access to ~s failed for ~s, reason: ~n~p~n", [Date, URI, RemoteHost, Reason]); compact -> io_lib:format( "[~s] access to ~s failed for ~s, reason: ~w~n", [Date, URI, RemoteHost, Reason]) end.