Skip to content

Commit 501e843

Browse files
add script to load events of otel logs and traces
1 parent 0de10db commit 501e843

File tree

2 files changed

+438
-0
lines changed

2 files changed

+438
-0
lines changed
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
import http from 'k6/http';
2+
import { check, sleep } from 'k6';
3+
import exec from 'k6/execution';
4+
import encoding from 'k6/encoding';
5+
import { randomString, randomItem, randomIntBetween, uuidv4 } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
6+
7+
// config for load test, uncomment to perform load test for an hour
8+
// export const options = {
9+
// discardResponseBodies: true,
10+
// // Key configurations for avg load test in this section
11+
// stages: [
12+
// { duration: '5m', target: 10 },
13+
// { duration: '60m', target: 8 },
14+
// { duration: '5m', target: 0 },
15+
// ],
16+
// };
17+
18+
// default options for all tests
19+
export const options = {
20+
discardResponseBodies: true,
21+
scenarios: {
22+
contacts: {
23+
executor: 'constant-vus',
24+
vus: 10,
25+
duration: "5m",
26+
},
27+
},
28+
};
29+
30+
// Helper function to generate current ISO time
31+
function currentIsoTime() {
32+
let event = new Date();
33+
return event.toISOString();
34+
}
35+
36+
// Helper function to generate unix nano time
37+
function currentUnixNanoTime() {
38+
return new Date().toISOString();
39+
}
40+
41+
// Helper to generate trace ID (hex string)
42+
function generateTraceId() {
43+
return [...Array(32)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
44+
}
45+
46+
// Helper to generate span ID (hex string)
47+
function generateSpanId() {
48+
return [...Array(16)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
49+
}
50+
51+
// Generate HTTP methods
52+
function randomHttpMethod() {
53+
return randomItem(["GET", "POST", "PUT", "DELETE", "PATCH"]);
54+
}
55+
56+
// Generate API endpoints
57+
function randomApiEndpoint() {
58+
const endpoints = [
59+
"/api/products/{id}",
60+
"/api/cart",
61+
"/api/checkout",
62+
"/api/users/{id}",
63+
"/api/orders/{id}",
64+
"/api/recommendations",
65+
"/api/categories",
66+
"/api/search",
67+
"/api/auth/login",
68+
"/api/auth/logout"
69+
];
70+
71+
let endpoint = randomItem(endpoints);
72+
73+
// Replace {id} with random product/user ID if present
74+
if (endpoint.includes("{id}")) {
75+
const id = randomItem([
76+
"0PUK6V6EV0", "1YMWWN1N4O", "2ZYFJ3GM2N",
77+
"66VCHSJNUP", "6E92ZMYYFZ", "9SIQT8TOJO",
78+
"L9ECAV7KIM", "LS4PSXUNUM", "OLJCESPC7Z"
79+
]);
80+
endpoint = endpoint.replace("{id}", id);
81+
}
82+
83+
return endpoint;
84+
}
85+
86+
// Generate IP addresses
87+
function randomIpAddress() {
88+
return `172.18.0.${randomIntBetween(1, 40)}`;
89+
}
90+
91+
// Generate port number
92+
function randomPort() {
93+
return randomIntBetween(8000, 60000);
94+
}
95+
96+
function randomStatusCode() {
97+
return randomItem([200, 206, 304, 400, 404, 500, 503]);
98+
}
99+
100+
// Map status code to appropriate severity number and text
101+
function getSeverityFromStatusCode(statusCode) {
102+
// Define severity mapping based on status code ranges
103+
if (statusCode >= 100 && statusCode < 200) {
104+
// 1xx - Informational
105+
return { number: randomItem([9, 10, 11, 12]), text: "INFO" };
106+
} else if (statusCode >= 200 && statusCode < 300) {
107+
// 2xx - Success
108+
return { number: randomItem([9, 10, 11, 12]), text: "INFO" };
109+
} else if (statusCode >= 300 && statusCode < 400) {
110+
// 3xx - Redirection
111+
return { number: randomItem([9, 10, 11, 12]), text: "INFO" };
112+
} else if (statusCode >= 400 && statusCode < 500) {
113+
// 4xx - Client Error
114+
return { number: randomItem([13, 14, 15, 16]), text: "WARN" };
115+
} else if (statusCode >= 500) {
116+
// 5xx - Server Error
117+
const severityRoll = Math.random();
118+
if (severityRoll < 0.7) {
119+
return { number: randomItem([17, 18, 19, 20]), text: "ERROR" };
120+
} else {
121+
return { number: randomItem([21, 22, 23, 24]), text: "FATAL" };
122+
}
123+
} else {
124+
// Default or unknown
125+
return { number: 0, text: "SEVERITY_NUMBER_UNSPECIFIED" };
126+
}
127+
}
128+
129+
// Generate random user agent
130+
function randomUserAgent() {
131+
const userAgents = [
132+
"python-requests/2.32.3",
133+
"curl/7.88.1",
134+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
135+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15",
136+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36",
137+
"Mozilla/5.0 (iPhone; CPU iPhone OS 15_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
138+
"PostmanRuntime/7.29.0"
139+
];
140+
return randomItem(userAgents);
141+
}
142+
143+
// Generate service names
144+
function randomServiceName() {
145+
return randomItem([
146+
"frontend-proxy",
147+
"product-service",
148+
"cart-service",
149+
"user-service",
150+
"checkout-service",
151+
"recommendation-service",
152+
"auth-service"
153+
]);
154+
}
155+
156+
// Generate body content for log
157+
function generateLogBody(method, path, statusCode, userAgent) {
158+
const timestamp = currentIsoTime();
159+
const bytesSent = randomIntBetween(100, 2000);
160+
const duration = randomIntBetween(1, 100);
161+
const durationMs = randomIntBetween(1, 20);
162+
const requestId = uuidv4().replace(/-/g, '-');
163+
const upstreamAddress = `${randomIpAddress()}:8080`;
164+
const sourceAddress = randomIpAddress();
165+
const destAddress = randomIpAddress();
166+
const sourcePort = randomPort();
167+
const destPort = 8080;
168+
const clientPort = randomPort();
169+
170+
return `[${timestamp}] "${method} ${path} HTTP/1.1" ${statusCode} - via_upstream - "-" 0 ${bytesSent} ${duration} ${durationMs} "-" "${userAgent}" "${requestId}" "frontend-proxy:8080" "${upstreamAddress}" frontend ${sourceAddress}:${sourcePort} ${destAddress}:${destPort} ${sourceAddress}:${clientPort} - -\n`;
171+
}
172+
173+
// Generate a single OTEL log entry
174+
function generateOtelLog() {
175+
const method = randomHttpMethod();
176+
const path = randomApiEndpoint();
177+
const statusCode = randomStatusCode();
178+
const userAgent = randomUserAgent();
179+
const serviceName = randomServiceName();
180+
const traceId = randomId(32);
181+
const spanId = randomId(16);
182+
const timeUnixNano = currentUnixNanoTime();
183+
const destAddress = randomIpAddress();
184+
const serverAddress = randomIpAddress();
185+
const sourceAddress = randomIpAddress();
186+
const upstreamHost = randomIpAddress();
187+
188+
// Get severity based on status code
189+
const severity = getSeverityFromStatusCode(statusCode);
190+
191+
return {
192+
"body": generateLogBody(method, path, statusCode, userAgent),
193+
"observed_time_unix_nano": timeUnixNano, // Using the same value as time_unix_nano
194+
"destination.address": destAddress,
195+
"event.name": "proxy.access",
196+
"server.address": serverAddress,
197+
"source.address": sourceAddress,
198+
"upstream.cluster": randomItem(["frontend", "backend", "auth", "product"]),
199+
"upstream.host": upstreamHost,
200+
"user_agent.original": randomUserAgent(),
201+
"service.name": serviceName,
202+
"severity_number": severity.number,
203+
"severity_text": severity.text,
204+
"span_id": spanId,
205+
"time_unix_nano": timeUnixNano,
206+
"trace_id": traceId,
207+
"url.full": `http://${serviceName}:8080${path}`,
208+
"url.path": path,
209+
};
210+
}
211+
212+
// Generate a batch of OTEL logs
213+
function generateOtelLogs(count) {
214+
const logs = [];
215+
for (let i = 0; i < count; i++) {
216+
logs.push(generateOtelLog());
217+
}
218+
return logs;
219+
}
220+
221+
// Get events per call from environment variable
222+
function eventsPerCall() {
223+
return Number(__ENV.P_EVENTS_COUNT) || 100;
224+
}
225+
226+
export default function () {
227+
const url = `${__ENV.P_URL}/api/v1/ingest`;
228+
const credentials = `${__ENV.P_USERNAME}:${__ENV.P_PASSWORD}`;
229+
const encodedCredentials = encoding.b64encode(credentials);
230+
231+
const params = {
232+
headers: {
233+
'Content-Type': 'application/json',
234+
'Authorization': 'Basic ' + `${encodedCredentials}`,
235+
'X-P-STREAM': `${__ENV.P_STREAM}`,
236+
'X-P-META-Host': '10.116.0.3',
237+
'X-P-META-Source': 'otel-logs-generator'
238+
}
239+
};
240+
241+
let events = eventsPerCall();
242+
243+
let batchRequests = JSON.stringify(generateOtelLogs(events));
244+
245+
let response = http.post(url, batchRequests, params);
246+
let date = new Date();
247+
248+
if (!check(response, {
249+
'status code MUST be 200': (res) => res.status == 200,
250+
})) {
251+
console.log(`Time: ${date}, Response: ${response.status}`);
252+
}
253+
}

0 commit comments

Comments
 (0)