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 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 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 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 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
132fn 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
153fn 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
218fn 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}