1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%% 21-module(mod_log). 22 23%% Application internal API 24-export([error_log/2, security_log/2, report_error/2]). 25 26%% Callback API 27-export([do/1, load/2, store/2, remove/1]). 28 29-include("httpd.hrl"). 30-include("httpd_internal.hrl"). 31-define(VMODULE,"LOG"). 32 33%%%========================================================================= 34%%% API 35%%%========================================================================= 36 37%% security log 38security_log(Info, ReasonStr) -> 39 Date = httpd_util:custom_date(), 40 case httpd_log:security_entry(security_log, no_security_log, Info, 41 Date, ReasonStr) of 42 no_security_log -> 43 ok; 44 {Log, Entry} -> 45 io:format(Log, "~s", [Entry]) 46 end. 47 48%% error_log 49error_log(Info, Reason) -> 50 Date = httpd_util:custom_date(), 51 error_log(Info, Date, Reason). 52 53error_log(Info, Date, Reason) -> 54 case httpd_log:error_entry(error_log, no_error_log, 55 Info, Date, Reason) of 56 no_error_log -> 57 ok; 58 {Log, Entry} -> 59 io:format(Log, "~s", [Entry]) 60 end. 61 62report_error(ConfigDB, Error) -> 63 Date = httpd_util:custom_date(), 64 case httpd_log:error_report_entry(error_log, no_error_log, ConfigDB, 65 Date, Error) of 66 no_error_log -> 67 ok; 68 {Log, Entry} -> 69 io:format(Log, "~s", [Entry]) 70 end. 71 72%%%========================================================================= 73%%% CALLBACK API 74%%%========================================================================= 75%%-------------------------------------------------------------------------- 76%% do(ModData) -> {proceed, OldData} | {proceed, NewData} | {break, NewData} 77%% | done 78%% ModData = #mod{} 79%% 80%% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS 81%%------------------------------------------------------------------------- 82do(Info) -> 83 AuthUser = auth_user(Info#mod.data), 84 Date = httpd_util:custom_date(), 85 log_internal_info(Info,Date,Info#mod.data), 86 case proplists:get_value(status, Info#mod.data) of 87 %% A status code has been generated! 88 {StatusCode, _PhraseArgs, Reason} -> 89 transfer_log(Info,"-",AuthUser,Date,StatusCode,0), 90 if 91 StatusCode >= 400 -> 92 error_log(Info,Date,Reason); 93 true -> 94 not_an_error 95 end, 96 {proceed,Info#mod.data}; 97 %% No status code has been generated! 98 undefined -> 99 case proplists:get_value(response, Info#mod.data) of 100 {already_sent,StatusCode,Size} -> 101 transfer_log(Info,"-",AuthUser,Date,StatusCode,Size), 102 {proceed,Info#mod.data}; 103 {response, Head, _Body} -> 104 Size = content_length(Head), 105 Code = proplists:get_value(code,Head,unknown), 106 transfer_log(Info, "-", AuthUser, Date, Code, Size), 107 {proceed, Info#mod.data}; 108 {StatusCode, Response} -> 109 transfer_log(Info, "-", AuthUser, Date, StatusCode, 110 httpd_util:flatlength(Response)), 111 {proceed,Info#mod.data}; 112 undefined -> 113 transfer_log(Info,"-",AuthUser,Date,200,0), 114 {proceed,Info#mod.data} 115 end 116 end. 117 118%%-------------------------------------------------------------------------- 119%% load(Line, Context) -> eof | ok | {ok, NewContext} | 120%% {ok, NewContext, Directive} | 121%% {ok, NewContext, DirectiveList} | {error, Reason} 122%% Line = string() 123%% Context = NewContext = DirectiveList = [Directive] 124%% Directive = {DirectiveKey , DirectiveValue} 125%% DirectiveKey = DirectiveValue = term() 126%% Reason = term() 127%% 128%% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS 129%%------------------------------------------------------------------------- 130load("TransferLog " ++ TransferLog, []) -> 131 {ok,[],{transfer_log,string:strip(TransferLog)}}; 132load("ErrorLog " ++ ErrorLog, []) -> 133 {ok,[],{error_log,string:strip(ErrorLog)}}; 134load("SecurityLog " ++ SecurityLog, []) -> 135 {ok, [], {security_log, string:strip(SecurityLog)}}. 136 137%%-------------------------------------------------------------------------- 138%% store(Directive, DirectiveList) -> {ok, NewDirective} | 139%% {ok, [NewDirective]} | 140%% {error, Reason} 141%% Directive = {DirectiveKey , DirectiveValue} 142%% DirectiveKey = DirectiveValue = term() 143%% Reason = term() 144%% 145%% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS 146%%------------------------------------------------------------------------- 147store({transfer_log,TransferLog}, ConfigList) when is_list(TransferLog)-> 148 case create_log(TransferLog,ConfigList) of 149 {ok,TransferLogStream} -> 150 {ok,{transfer_log,TransferLogStream}}; 151 {error,Reason} -> 152 {error,Reason} 153 end; 154store({transfer_log,TransferLog}, _) -> 155 {error, {wrong_type, {transfer_log, TransferLog}}}; 156store({error_log,ErrorLog}, ConfigList) when is_list(ErrorLog) -> 157 case create_log(ErrorLog,ConfigList) of 158 {ok,ErrorLogStream} -> 159 {ok,{error_log,ErrorLogStream}}; 160 {error,Reason} -> 161 {error,Reason} 162 end; 163store({error_log,ErrorLog}, _) -> 164 {error, {wrong_type, {error_log, ErrorLog}}}; 165store({security_log, SecurityLog}, ConfigList) when is_list(SecurityLog) -> 166 case create_log(SecurityLog, ConfigList) of 167 {ok, SecurityLogStream} -> 168 {ok, {security_log, SecurityLogStream}}; 169 {error, Reason} -> 170 {error, Reason} 171 end; 172store({security_log, SecurityLog}, _) -> 173 {error, {wrong_type, {security_log, SecurityLog}}}. 174 175%%-------------------------------------------------------------------------- 176%% remove(ConfigDb) -> _ 177%% 178%% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS 179%%------------------------------------------------------------------------- 180remove(ConfigDB) -> 181 lists:foreach(fun([Stream]) -> file:close(Stream) end, 182 ets:match(ConfigDB,{transfer_log,'$1'})), 183 lists:foreach(fun([Stream]) -> file:close(Stream) end, 184 ets:match(ConfigDB,{error_log,'$1'})), 185 lists:foreach(fun([Stream]) -> file:close(Stream) end, 186 ets:match(ConfigDB,{security_log,'$1'})), 187 ok. 188 189%%%======================================================================== 190%%% Internal functions 191%%%======================================================================== 192%% transfer_log 193transfer_log(Info,RFC931,AuthUser,Date,StatusCode,Bytes) -> 194 case httpd_log:access_entry(transfer_log, no_transfer_log, 195 Info, RFC931, AuthUser, Date, 196 StatusCode, Bytes) of 197 no_transfer_log -> 198 ok; 199 {Log, Entry} -> 200 io:format(Log, "~s", [Entry]) 201 end. 202 203create_log(LogFile, ConfigList) -> 204 Filename = string:strip(LogFile), 205 case filename:pathtype(Filename) of 206 absolute -> 207 case file:open(Filename, [read, write]) of 208 {ok,LogStream} -> 209 file:position(LogStream,{eof,0}), 210 {ok,LogStream}; 211 {error,_} -> 212 {error,?NICE("Can't create "++Filename)} 213 end; 214 volumerelative -> 215 case file:open(Filename, [read, write]) of 216 {ok,LogStream} -> 217 file:position(LogStream,{eof,0}), 218 {ok,LogStream}; 219 {error,_} -> 220 {error,?NICE("Can't create "++Filename)} 221 end; 222 relative -> 223 case proplists:get_value(server_root,ConfigList) of 224 undefined -> 225 {error, 226 ?NICE(Filename++ 227 " is an invalid logfile name beacuse " 228 "ServerRoot is not defined")}; 229 ServerRoot -> 230 AbsoluteFilename=filename:join(ServerRoot,Filename), 231 case file:open(AbsoluteFilename, [read, write]) of 232 {ok,LogStream} -> 233 file:position(LogStream,{eof,0}), 234 {ok,LogStream}; 235 {error, _Reason} -> 236 {error,?NICE("Can't create "++AbsoluteFilename)} 237 end 238 end 239 end. 240 241%% log_internal_info 242log_internal_info(_Info, _Date, []) -> 243 ok; 244log_internal_info(Info,Date,[{internal_info,Reason}|Rest]) -> 245 error_log(Info, Date, Reason), 246 log_internal_info(Info,Date,Rest); 247log_internal_info(Info,Date,[_|Rest]) -> 248 log_internal_info(Info,Date,Rest). 249 250auth_user(Data) -> 251 case proplists:get_value(remote_user, Data) of 252 undefined -> 253 "-"; 254 RemoteUser -> 255 RemoteUser 256 end. 257 258content_length(Head) -> 259 case proplists:get_value(content_length, Head) of 260 undefined -> 261 unknown; 262 Size -> 263 list_to_integer(Size) 264 end. 265