Created
December 23, 2025 09:03
-
-
Save andsel/d3b372b90bd66e0db98a6acc1ac32c80 to your computer and use it in GitHub Desktop.
Simple plain text traffic loader for Logstash
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ///usr/bin/env jbang "$0" "$@" ; exit $? | |
| //DESCRIPTION A traffic simulation application | |
| //DEPS info.picocli:picocli:4.6.3 | |
| import picocli.CommandLine; | |
| import picocli.CommandLine.Command; | |
| import picocli.CommandLine.Option; | |
| import picocli.CommandLine.Parameters; | |
| import java.io.OutputStream; | |
| import java.io.OutputStreamWriter; | |
| import java.io.PrintWriter; | |
| import java.io.Writer; | |
| import java.net.Socket; | |
| import java.time.Duration; | |
| import java.time.LocalDateTime; | |
| import java.net.ConnectException; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import java.util.Random; | |
| import java.util.concurrent.Callable; | |
| @Command(name = "traffic-simulator", mixinStandardHelpOptions = true, version = "traffic-simulator 0.1", | |
| description = "A traffic simulation application") | |
| class TrafficSimulator implements Callable<Integer> { | |
| @Option(names = {"-h", "--host"}, description = "The remote host to connect to", defaultValue = "localhost") | |
| private String host = "localhost"; | |
| @Option(names = {"-p", "--port"}, description = "The port number to connect to", defaultValue = "3333") | |
| private int port = 3333; | |
| @Option(names = {"--mean-size"}, description = "Mean message size in characters", defaultValue = "50") | |
| private int meanSize = 50; | |
| @Option(names = {"--delta"}, description = "Message size variation (+/- delta)", defaultValue = "20") | |
| private int delta = 20; | |
| private final Random random = new Random(); | |
| /** | |
| * Generates a message with variable size based on mean +/- delta | |
| * @param meanSize the target mean size of the message | |
| * @param delta the variation range (message size will be between meanSize-delta and meanSize+delta) | |
| * @return a generated message string | |
| */ | |
| private String generateMessage(int meanSize, int delta) { | |
| int actualSize = Math.max(1, meanSize - delta + random.nextInt(2 * delta + 1)); | |
| StringBuilder message = new StringBuilder(actualSize); | |
| // Fill with readable characters | |
| // String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 "; | |
| for (int i = 0; i < actualSize; i++) { | |
| // message.append(chars.charAt(random.nextInt(chars.length()))); | |
| message.append("a"); | |
| } | |
| return message.toString(); | |
| } | |
| private void sendBatch(PrintWriter printWriter, int meanSize, int delta, int batchSize) { | |
| for (int i = 0; i < batchSize; i++) { | |
| String message = generateMessage(meanSize, delta); | |
| printWriter.println(message); | |
| } | |
| printWriter.flush(); | |
| } | |
| public static void main(String... args) { | |
| int exitCode = new CommandLine(new TrafficSimulator()).execute(args); | |
| System.exit(exitCode); | |
| } | |
| record StressPhase(String name, Duration duration, int meanSize, int delta, int batchSize) {} | |
| final int batchSize = 100; | |
| final List<StressPhase> experimentPhases = Arrays.asList( | |
| new StressPhase("1 minute", Duration.ofMinutes(1), 4 * 1024, 200, batchSize), | |
| new StressPhase("5 minutes", Duration.ofMinutes(4), 2 * 1024, 100, batchSize), | |
| new StressPhase("15 minutes", Duration.ofMinutes(10), 1024, 50, batchSize) | |
| ); | |
| @Override | |
| public Integer call() throws Exception { | |
| System.out.println("Starting traffic simulation to " + host + ":" + port + "..."); | |
| // Create a socket and connect to the host and port | |
| Socket socket = null; | |
| try { | |
| socket = new Socket(host, port); | |
| } catch (ConnectException e) { | |
| System.out.println("Failed to connect to " + host + ":" + port + ": " + e.getMessage()); | |
| return 1; | |
| } | |
| // Get the output stream | |
| // Wrap with PrintWriter for newline support | |
| PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); | |
| for (StressPhase phase : experimentPhases) { | |
| System.out.println("Starting phase: " + phase.name() + ", " + LocalDateTime.now()); | |
| long startTime = System.currentTimeMillis(); | |
| while (System.currentTimeMillis() - startTime < phase.duration.toMillis()) { | |
| // TODO now the number of messages per batch is fixed, make it little bit more dynamic to different numbers in percentiles. | |
| // create a what should be a single batch on Logstash side | |
| sendBatch(printWriter, phase.meanSize, phase.delta, phase.batchSize); | |
| Thread.sleep(20); // sleep an interval shorter than the batch interval (pipeline.batch.delay default 50 ms) | |
| } | |
| } | |
| printWriter.close(); | |
| // Close the socket | |
| socket.close(); | |
| // TODO: Implement traffic simulation logic | |
| System.out.println("Traffic simulation completed!"); | |
| return 0; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment