fakedata/
logs.rs

1use chrono::{
2    format::{DelayedFormat, StrftimeItems},
3    prelude::Local,
4    SecondsFormat,
5};
6use fakedata_generator::{gen_domain, gen_ipv4, gen_username};
7use rand::{rng, Rng};
8
9static APPLICATION_NAMES: [&str; 10] = [
10    "auth", "data", "deploy", "etl", "scraper", "cron", "ingress", "egress", "alerter", "fwd",
11];
12
13static ERROR_LEVELS: [&str; 9] = [
14    "alert", "crit", "debug", "emerg", "error", "info", "notice", "trace1-8", "warn",
15];
16
17static HTTP_CODES: [usize; 15] = [
18    200, 300, 301, 302, 304, 307, 400, 401, 403, 404, 410, 500, 501, 503, 550,
19];
20
21static HTTP_VERSIONS: [&str; 3] = ["HTTP/1.0", "HTTP/1.1", "HTTP/2.0"];
22static HTTP_METHODS: [&str; 7] = ["DELETE", "GET", "HEAD", "OPTION", "PATCH", "POST", "PUT"];
23
24static HTTP_ENDPOINTS: [&str; 9] = [
25    "/wp-admin",
26    "/controller/setup",
27    "/user/booperbot124",
28    "/apps/deploy",
29    "/observability/metrics/production",
30    "/secret-info/open-sesame",
31    "/booper/bopper/mooper/mopper",
32    "/do-not-access/needs-work",
33    "/this/endpoint/prints/money",
34];
35
36static ERROR_MESSAGES: [&str; 9] = [
37    "There's a breach in the warp core, captain",
38    "Great Scott! We're never gonna reach 88 mph with the flux capacitor in its current state!",
39    "You're not gonna believe what just happened",
40    "#hugops to everyone who has to deal with this",
41    "Take a breath, let it go, walk away",
42    "A bug was encountered but not in Vector, which doesn't have bugs",
43    "We're gonna need a bigger boat",
44    "Maybe we just shouldn't use computers",
45    "Pretty pretty pretty good",
46];
47
48const APACHE_COMMON_TIME_FORMAT: &str = "%d/%b/%Y:%T %z";
49const APACHE_ERROR_TIME_FORMAT: &str = "%a %b %d %T %Y";
50const SYSLOG_3164_FORMAT: &str = "%b %d %T";
51const JSON_TIME_FORMAT: &str = "%d/%b/%Y:%T";
52
53pub fn apache_common_log_line() -> String {
54    // Example log line:
55    // 173.159.239.159 - schoen1464 [31/Oct/2020:19:06:10 -0700] "POST /wireless HTTP/2.0" 100 20815
56    format!(
57        "{} - {} [{}] \"{} {} {}\" {} {}",
58        ipv4_address(),
59        username(),
60        timestamp_apache_common(),
61        http_method(),
62        http_endpoint(),
63        http_version(),
64        http_code(),
65        byte_size(),
66    )
67}
68
69pub fn apache_error_log_line() -> String {
70    // Example log line:
71    // [Sat Oct 31 19:27:55 2020] [deleniti:crit] [pid 879:tid 9607] [client 169.198.228.174:1364] Something bad happened
72    format!(
73        "[{}] [{}:{}] [pid {}:tid] [client {}:{}] {}",
74        timestamp_apache_error(),
75        username(),
76        error_level(),
77        pid(),
78        ipv4_address(),
79        port(),
80        error_message(),
81    )
82}
83
84pub fn syslog_3164_log_line() -> String {
85    format!(
86        "<{}>{} {} {}[{}]: {}",
87        priority(),
88        timestamp_syslog_3164(),
89        domain(),
90        application(),
91        pid(),
92        error_message()
93    )
94}
95
96pub fn syslog_5424_log_line() -> String {
97    // Example log line:
98    // <65>2 2020-11-05T18:11:43.975Z chiefubiquitous.io totam 6899 ID44 - Something bad happened
99    format!(
100        "<{}>{} {} {} {} {} ID{} - {}",
101        priority(),
102        syslog_version(),
103        timestamp_syslog_5424(),
104        domain(),
105        username(),
106        random_in_range(100, 9999),
107        random_in_range(1, 999),
108        error_message(),
109    )
110}
111
112pub fn json_log_line() -> String {
113    // Borrowed from Flog: https://github.com/mingrammer/flog/blob/master/log.go#L24
114    // Example log line:
115    // {"host":"208.171.64.160", "user-identifier":"hoppe7055", "datetime":" -0800", "method": \
116    //   "PATCH", "request": "/web+services/cross-media/strategize", "protocol":"HTTP/1.1", \
117    //   "status":403, "bytes":25926, "referer": "https://www.leadworld-class.org/revolutionize/applications"}
118    format!(
119        "{{\"host\":\"{}\",\"user-identifier\":\"{}\",\"datetime\":\"{}\",\"method\":\"{}\",\"request\":\"{}\",\"protocol\":\"{}\",\"status\":\"{}\",\"bytes\":{},\"referer\":\"{}\"}}",
120        ipv4_address(),
121        username(),
122        timestamp_json(),
123        http_method(),
124        http_endpoint(),
125        http_version(),
126        http_code(),
127        random_in_range(1000, 50000),
128        referer(),
129    )
130}
131
132// Formatted timestamps
133fn timestamp_apache_common() -> DelayedFormat<StrftimeItems<'static>> {
134    Local::now().format(APACHE_COMMON_TIME_FORMAT)
135}
136
137fn timestamp_apache_error() -> DelayedFormat<StrftimeItems<'static>> {
138    Local::now().format(APACHE_ERROR_TIME_FORMAT)
139}
140
141fn timestamp_syslog_3164() -> DelayedFormat<StrftimeItems<'static>> {
142    Local::now().format(SYSLOG_3164_FORMAT)
143}
144
145fn timestamp_syslog_5424() -> String {
146    Local::now().to_rfc3339_opts(SecondsFormat::Millis, true)
147}
148
149fn timestamp_json() -> DelayedFormat<StrftimeItems<'static>> {
150    Local::now().format(JSON_TIME_FORMAT)
151}
152
153// Other random strings
154fn application() -> &'static str {
155    random_from_array(&APPLICATION_NAMES)
156}
157
158fn domain() -> String {
159    gen_domain()
160}
161
162fn error_level() -> &'static str {
163    random_from_array(&ERROR_LEVELS)
164}
165
166fn error_message() -> &'static str {
167    random_from_array(&ERROR_MESSAGES)
168}
169
170fn http_code() -> usize {
171    random_from_array_copied(&HTTP_CODES)
172}
173
174fn byte_size() -> usize {
175    random_in_range(50, 50000)
176}
177
178fn http_endpoint() -> &'static str {
179    random_from_array(&HTTP_ENDPOINTS)
180}
181
182fn http_method() -> &'static str {
183    random_from_array(&HTTP_METHODS)
184}
185
186fn http_version() -> &'static str {
187    random_from_array(&HTTP_VERSIONS)
188}
189
190fn ipv4_address() -> String {
191    gen_ipv4()
192}
193
194fn pid() -> usize {
195    random_in_range(1, 9999)
196}
197
198fn port() -> usize {
199    random_in_range(1024, 65535)
200}
201
202fn priority() -> usize {
203    random_in_range(0, 191)
204}
205
206fn referer() -> String {
207    format!("https://{}{}", domain(), http_endpoint())
208}
209
210fn username() -> String {
211    gen_username()
212}
213
214fn syslog_version() -> usize {
215    random_in_range(1, 3)
216}
217
218// Helper functions
219fn random_in_range(min: usize, max: usize) -> usize {
220    rng().random_range(min..max)
221}
222
223fn random_from_array<T: ?Sized>(v: &'static [&'static T]) -> &'static T {
224    v[rng().random_range(0..v.len())]
225}
226
227fn random_from_array_copied<T: Copy>(v: &[T]) -> T {
228    v[rng().random_range(0..v.len())]
229}