fakedata/
logs.rs

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