Skip to content

Instantly share code, notes, and snippets.

@tanishiking
Last active August 12, 2016 14:27
Show Gist options
  • Save tanishiking/48bb1fe147c0e2457778032f9724c7b1 to your computer and use it in GitHub Desktop.
Save tanishiking/48bb1fe147c0e2457778032f9724c7b1 to your computer and use it in GitHub Desktop.
host:127.0.0.1 user:frank epoch:1372694390 req:GET /apache_pb.gif HTTP/1.0 status:200 size:2326 referer:http://www.hatena.ne.jp/
host:127.0.0.1 user:john epoch:1372794390 req:GET /apache_pb.gif HTTP/1.0 status:200 size:1234 referer:http://b.hatena.ne.jp/hotentry
host:127.0.0.1 user:- epoch:1372894390 req:GET /apache_pb.gif HTTP/1.0 status:503 size:9999 referer:http://www.example.com/start.html
host:127.0.0.1 user:frank epoch:1372694390 req:GET /apache_pb.gif HTTP/1.0 status:500 size:2326 referer:http://www.hatena.ne.jp/
host:127.0.0.1 user:frank epoch:1372794395 req:GET /notfound.gif HTTP/1.0 status:404 size:100 referer:-
OCAMLOPT=ocamlopt
TARGETS=parse
INCLUDES=str.cmxa
SRCS=utils.ml parser.ml
OBJS=$(SRCS:.ml=.cmx)
all: $(TARGETS) $(OBJS)
$(TARGETS): $(OBJS)
$(OCAMLOPT) -o $@ $(INCLUDES) $(OBJS)
.SUFFIXES: .ml .mli .cmo .cmi .cmx
.ml.cmx:
$(OCAMLOPT) -c $<
clean:
$(RM) *~ $(TARGETS) *.cm[iox] *.o
.PHONY: clean
type log_entry = {
req_method: string;
req_path: string;
req_protocol: string;
req_url: string;
req_time: int;
}
module EntryMap = Map.Make(String)
let print_log_entry log_entry =
print_string ("method: " ^ log_entry.req_method ^ "\n");
print_string ("path: " ^ log_entry.req_path ^ "\n");
print_string ("protocol: " ^ log_entry.req_protocol ^ "\n");
print_string ("url: " ^ log_entry.req_url ^ "\n");
print_string ("time: " ^ (string_of_int log_entry.req_time) ^ "\n");
print_string "\n"
let entry_map_find_or_else k v entry_map =
try EntryMap.find k entry_map
with _ -> v
let split_once input delimiter =
let splitted = Str.split (Str.regexp_string delimiter) input in
if List.length splitted < 2 then (input, "")
else (List.hd splitted, String.concat "" (List.tl splitted))
let parse_line line =
let elems = Str.split (Str.regexp_string "\t") line in
let entry_map = List.fold_left
(fun acc elem ->
let (k, v) = split_once elem ":" in
EntryMap.add k v acc)
EntryMap.empty
elems in
let host = (entry_map_find_or_else "host" "-" entry_map) in
let epoch = int_of_string (entry_map_find_or_else "epoch" "0" entry_map) in
let req = (entry_map_find_or_else "req" "-" entry_map) in
let req_info = Str.split (Str.regexp_string " ") req in
try
let req_method = List.nth req_info 0 in
let req_path = List.nth req_info 1 in
let req_protocol = List.nth req_info 2 in
{ req_method = req_method;
req_path = req_path;
req_protocol = req_protocol;
req_url = "http://" ^ host ^ req_path;
req_time = epoch }
with _ ->
let (req_method, req_path, req_protocol) = ("-", "-", "-") in
{ req_method = req_method;
req_path = req_path;
req_protocol = req_protocol;
req_url = "http://" ^ host ^ req_path;
req_time = epoch }
let line_stream_of_channel channel =
Stream.from
(fun _ -> try Some (input_line channel)
with End_of_file -> None)
let _ =
let len = Array.length Sys.argv in
if len = 2 then
let file_path = Sys.argv.(1) in
let ic = open_in file_path in
let lines = line_stream_of_channel ic in
try
let entry_stream = Utils.Stream.map parse_line lines in
Stream.iter print_log_entry entry_stream;
close_in ic
with e ->
close_in ic;
raise e
else
print_string "Invalid number of argument\n"
module Stream = struct
let fold f stream init =
let res = ref init in
Stream.iter
(fun x -> res := f x !res)
stream;
!res
let map f stream =
let rec next i =
try Some (f (Stream.next stream))
with Stream.Failure -> None in
Stream.from next
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment