Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[feature] HttpServer and RemoteLog: push logs to a remote log server …

…(experimental)
  • Loading branch information...
commit 3062e570066a5a5ea66f33735dce9fbb7395ab06 1 parent 4c6cb9f
@cedricss cedricss authored
View
24 libnet/httpServer.ml
@@ -39,6 +39,12 @@ type request = HST.request
let make_status = HSC.make_status
+let remote_logs_params = ref None
+
+(* Warning: it only returns the last defined remote-logs server option *)
+(* TODO: getter for a specific http server name *)
+let get_remote_logs_params() = !remote_logs_params
+
(* Private tools *)
let get_content_length req = Int64.to_int (Option.default 0L (HSC.get_Content_Length req.HST.request_header))
@@ -508,6 +514,7 @@ type options =
maximum_number_of_connections: int;
maximum_content_length: int;
maximum_number_of_headers: int;
+ remote_logs: HST.remote_logs option;
favicon_ico: HSC.body_value;
favicon_gif: HSC.body_value;
backtrace: bool;
@@ -594,6 +601,7 @@ let default_options =
maximum_number_of_connections = max_int;
maximum_content_length = (50*1024*1024);
maximum_number_of_headers = 200;
+ remote_logs = None;
favicon_ico = null_body_value (*(body_value_from_home ~log:true ".favicon.ico")*);
favicon_gif = null_body_value (*(body_value_from_home ~log:true ".favicon.gif")*);
backtrace = true;
@@ -729,6 +737,21 @@ let spec_args name =
ServerArg.func ServerArg.float (fun o f -> { o with server_write_timeout = Time.seconds_float f }),
"<float>", (sprintf "Timeout while writing data (default: %6.1f)" (Time.in_seconds default_options.server_write_timeout));
+ p"remote-logs",
+ ServerArg.func ServerArg.string (fun o s ->
+ try
+ let (hostname,port_appkey) = Base.String.split_char ':' s in
+ let (port,appkey) = Base.String.split_char '/' port_appkey in
+ let port = int_of_string port in
+ let remote_logs = Some {HST.hostname=hostname; HST.port=port; HST.appkey=appkey} in
+ remote_logs_params := remote_logs;
+ {o with remote_logs = remote_logs}
+ with
+ | Not_found -> let _ = prerr_endline ("Bad option \""^s^"\" for --remote-logs") in o
+ | Failure s -> let _ = prerr_endline ("Invalid port for --remote-logs."^s) in o
+ ),
+ "<hostname:port/appkey>", "Log access to a remote server (WARNING: this is experimental) (default: no log server).";
+
(*(p"max-connections")@["-C"],
ServerArg.func ServerArg.int (fun o i -> { o with maximum_number_of_connections = i }),
"<int>", "Maximum number of active server connections (default: 100)";*)
@@ -865,6 +888,7 @@ let make (name:string) (opt:options) (sched:Scheduler.t) : t =
rt_maximum_content_length = opt.maximum_content_length;
rt_maximum_number_of_headers = opt.maximum_number_of_headers;
rt_log_accesses = (!log_accesses);
+ rt_remote_logs = opt.remote_logs;
rt_time_diff = !(HST.time_diff);
rt_plim = 128;
};
View
14 libnet/httpServerCore.proto
@@ -1,7 +1,7 @@
% -*-erlang-*-
%
-% Copyright © 2011 MLstate
+% Copyright © 2011, 2012 MLstate
%
% This file is part of OPA.
%
@@ -54,6 +54,7 @@
rt_maximum_content_length : int;
rt_maximum_number_of_headers : int;
rt_log_accesses : bool;
+ rt_remote_logs : HttpServerTypes.remote_logs option;
rt_time_diff : string;
rt_plim : int;
}
@@ -178,13 +179,22 @@ let access_log runtime request_line response =
if runtime.rt_core.rt_log_accesses
then
let host = runtime.rt_tmp.rt_hr.hr_inet_addr_str in
+ let cookie = runtime.rt_tmp.rt_hr.hr_ic in
let _method = String.trim (string_of_msg request_line) in
let status = match response.sl with | Sl (_,code,_) -> string_of_int code | _ -> "-" in
let bytes = content_length response.body in
let ua = runtime.rt_tmp.rt_hr.hr_user_agent in
let referer = runtime.rt_tmp.rt_hr.hr_referer in
(* Combined log format (apparently) *)
- Logger.log_access "%s - - [%s] \"%s\" %s %d %s %s" host !current_time_string _method status bytes referer ua
+ let _ = Logger.log_access "%s - - [%s] \"%s\" %s %d %s %s" host !current_time_string _method status bytes referer ua in
+ (
+ match runtime.rt_core.rt_remote_logs with
+ | None -> ()
+ | Some opt -> (
+ let encode s = Encodings.encode_uri_component (Encodings.encode_uri_component s) in
+ Http_client.get Scheduler.default opt.hostname opt.port (Printf.sprintf "/?appkey=%s&kind=ping&method=%s&status=%s&bytes=%d&cookie=%s&host=%s&referer=%s&ua=%s" opt.appkey (encode _method) (encode status) bytes cookie (encode host) (encode referer) (encode ua)) (fun _ -> ())
+ )
+ )
else ()
let get_payload runtime = runtime.rt_proto.rt_payload
let set_payload runtime payload = { runtime with rt_proto={ runtime.rt_proto with rt_payload=payload; }; }
View
2  libnet/httpServerTypes.ml
@@ -70,5 +70,7 @@ type web_info = { cont : response -> unit;
certificate : Ssl.certificate option;
}
+type remote_logs = {port : int; hostname : string; appkey : string}
+
let current_time_string = ref ""
let time_diff = ref ""
View
2  libnet/httpServerTypes.mli
@@ -70,5 +70,7 @@ type web_info = { cont : response -> unit;
certificate : Ssl.certificate option;
}
+type remote_logs = {port : int; hostname : string; appkey : string}
+
val current_time_string : string ref
val time_diff : string ref
View
8 opabsl/mlbsl/bslNet.ml
@@ -32,6 +32,7 @@ let default_scheduler = BslScheduler.opa
##extern-type HttpRequest.payload = HttpServerCore.payload
##extern-type HttpRequest.msg_list = HttpServerCore_parse.msg list
##extern-type HttpRequest.request = HttpServerTypes.request
+##extern-type remote_logs = HttpServerTypes.remote_logs option
##opa-type HttpRequest.part
@@ -384,6 +385,13 @@ let default_scheduler = BslScheduler.opa
| Unix.ADDR_INET(addr,_port) -> Unix.string_of_inet_addr(addr)
| _ -> assert false
+ ##register get_remote_logs_params : -> opa[option(tuple_3(string, int, string))]
+ let get_remote_logs_params _ =
+ match HttpServer.get_remote_logs_params () with
+ | None -> ServerLib.none
+ | Some p -> ServerLib.some (BslNativeLib.opa_tuple_3
+ (p.HttpServerTypes.hostname, p.HttpServerTypes.port, p.HttpServerTypes.appkey))
+
##endmodule
##module ssl
View
85 stdlib/core/web/server/remote_log.opa
@@ -0,0 +1,85 @@
+/*
+ Copyright © 2011 MLstate
+
+ This file is part of OPA.
+
+ OPA is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License, version 3, as published by
+ the Free Software Foundation.
+
+ OPA is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with OPA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * RemoteLog module
+ *
+ * @author: Cedric Soulas, 2011
+ */
+
+/**
+ * {1 About this module}
+ *
+ * Log any kind of events to a remote server, via a simple http GET request.
+ * Example: http://hostname:port/?appkey=key&cookie=f8a0qb9sq98fs&event1=v1&event2=v2
+ * This remote log server is specified with the "--remote-logs" option.
+ *
+ * WARNING: this is an experimental feature.
+ *
+ */
+
+import stdlib.core.web.client
+import stdlib.core
+
+/**
+ * {1 Interface}
+ */
+RemoteLog = {{
+
+ @private
+ get_remote_logs_params = %% BslNet.Http_server.get_remote_logs_params %% : -> option((string, int, string))
+
+ @private
+ remote_uri_prefix() =
+ match get_remote_logs_params() with
+ | {none} -> {none}
+ | {some=(hostname,port,appkey)} ->
+ cookie = match ThreadContext.get({current}).key with
+ | {client = {~client ...}} -> "&cookie={client}"
+ | _ -> ""
+ some("http://{hostname}:{port}/?appkey={appkey}{cookie}")
+
+ /*
+ * Log a list of events to a remote server.
+ * WARNING: this is an experimental feature.
+ *
+ * @param event_list a list of ("key", "value") events to be sent to the remote log server. The value is encoded, not the key.
+ */
+ info(event_list) =
+ match remote_uri_prefix() with
+ | {none} -> Log.error("Remote log server","Bad uri prefix: {remote_uri_prefix}")
+ | {some=uri} -> (
+ uri = List.fold(((key,value), acc ->
+ value = Uri.encode_string(value)
+ "{acc}&{key}={value}"), event_list, uri)
+ match Uri.of_string(uri) with
+ | {none} -> Log.error("Remote log server","Bad uri: {uri}")
+ | {some=uri} -> WebClient.Get.try_get_async(uri, (_ -> void))
+ )
+
+ /*
+ * Same as RemoteLog.info but adding a ("error", "1") to the event list.
+ */
+ error(event_list) = info([("error","1")|event_list])
+
+ /*
+ * Same as RemoteLog.info but adding a ("error", "2") to the event list.
+ */
+ fatal(event_list) = info([("error","2")|event_list])
+
+}}
Please sign in to comment.
Something went wrong with that request. Please try again.