-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaccess_log.ion
More file actions
137 lines (120 loc) · 3.57 KB
/
Copy pathaccess_log.ion
File metadata and controls
137 lines (120 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Access log analyzer: scan log lines for HTTP status codes, classify them,
// and count server errors on a background thread while the main thread parses.
import "stdlib/fmt.ion" as fmt;
import "stdlib/io.ion" as io;
enum HttpClass {
Success;
ClientError;
ServerError;
}
fn line_at(index: int) -> String {
if index == 0 {
return String::from("GET /health 200 OK");
} else if index == 1 {
return String::from("POST /login 401 Unauthorized");
} else if index == 2 {
return String::from("GET /missing 404 Not Found");
} else if index == 3 {
return String::from("GET /down 503 Service Unavailable");
} else {
return String::from("malformed line with no status");
}
}
fn parse_status_from_line(line: String) -> int {
let mut last: int = 0;
let mut current: int = 0;
let mut in_run: bool = false;
for ch in line {
if ch >= 48 && ch <= 57 {
if !in_run {
current = 0;
in_run = true;
}
current = current * 10 + ((ch as int) - 48);
} else {
if in_run {
last = current;
in_run = false;
}
}
}
if in_run {
last = current;
}
return last;
}
// Parse the last digit run from a log line at the given index.
fn parse_line_at(index: int) -> int {
let line: String = line_at(index);
return parse_status_from_line(line);
}
fn scan_logs(code_tx: Sender<int>, expected: int) -> int {
let mut auth_failures: int = 0;
let mut parsed: int = 0;
let log_indices: [int; 5] = [0, 1, 2, 3, 4];
for index in log_indices {
let code: int = parse_line_at(index);
if code == 0 {
continue;
}
if parsed >= expected {
break;
}
let mut kind: HttpClass = HttpClass::ClientError;
if code >= 200 && code < 300 {
kind = HttpClass::Success;
} else if code >= 400 && code < 500 {
kind = HttpClass::ClientError;
} else if code >= 500 && code < 600 {
kind = HttpClass::ServerError;
}
match kind {
HttpClass::ClientError if code == 401 => {
auth_failures += 1;
}
HttpClass::ClientError => {}
HttpClass::ServerError => {}
HttpClass::Success => {}
};
send(&code_tx, code);
parsed += 1;
}
return auth_failures;
}
fn valid_log_count() -> int {
return 4;
}
fn main() -> int {
let (code_tx, code_rx): (Sender<int>, Receiver<int>) = channel<int>();
let (done_tx, done_rx): (Sender<int>, Receiver<int>) = channel<int>();
spawn {
let mut rx: Receiver<int> = code_rx;
let mut server_errors: int = 0;
let mut received: int = 0;
loop {
if received >= valid_log_count() {
break;
}
let code: int = recv(&mut rx);
if code >= 500 {
server_errors += 1;
}
received += 1;
}
send(&done_tx, server_errors);
};
let auth_failures: int = scan_logs(code_tx, valid_log_count());
let mut done_rx_mut: Receiver<int> = done_rx;
let server_errors: int = recv(&mut done_rx_mut);
if server_errors != 1 {
return 1;
}
if auth_failures != 1 {
return 2;
}
let server_line: String = fmt::int_to_string(server_errors);
io::println(server_line);
let auth_line: String = fmt::int_to_string(auth_failures);
io::println(auth_line);
return 0;
}