package com.example.startup; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import java.lang.management.ManagementFactory; import java.net.DatagramSocket; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; @Slf4j @Component public class AdvancedStartupLogger implements ApplicationListener { private final Environment env; private static final Instant START_TIME = Instant.now(); public AdvancedStartupLogger(Environment env) { this.env = env; } @Override public void onApplicationEvent(WebServerInitializedEvent event) { int port = event.getWebServer().getPort(); String protocol = resolveProtocol(); String contextPath = resolveContextPath(); String appName = env.getProperty("spring.application.name", "application"); String profiles = Arrays.toString(env.getActiveProfiles()); String pid = getPid(); String javaVersion = System.getProperty("java.version"); String outboundIp = getOutboundIp(); boolean docker = isDocker(); boolean k8s = isK8s(); long startupMs = Duration.between(START_TIME, Instant.now()).toMillis(); List allIps = getAllNetworkIps(); long maxHeapMb = Runtime.getRuntime().maxMemory() / 1024 / 1024; String actuatorPath = env.getProperty("management.endpoints.web.base-path", "actuator"); log.info("\n" + "================= 🚀 SERVICE STARTED =================\n" + "App Name : {}\n" + "PID : {}\n" + "Profiles : {}\n" + "Java Version : {}\n" + "Startup Time : {} ms\n" + "Max Heap : {} MB\n\n" + "Access URLs:\n" + "Local : {}://localhost:{}{}\n" + "External : {}://{}:{}{}\n" + "Actuator : {}://{}:{}{}{}\n\n" + "All Network IPs : {}\n" + "Docker : {}\n" + "Kubernetes : {}\n" + "=======================================================", appName, pid, profiles, javaVersion, startupMs, maxHeapMb, protocol, port, contextPath, protocol, outboundIp, port, contextPath, protocol, outboundIp, port, contextPath, actuatorPath, allIps, docker, k8s ); logStructuredJson(appName, port, outboundIp, startupMs); } private String resolveProtocol() { return env.getProperty("server.ssl.key-store") != null ? "https" : "http"; } private String resolveContextPath() { return env.getProperty("server.servlet.context-path", ""); } private String getPid() { return ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; } private boolean isDocker() { return new java.io.File("/.dockerenv").exists(); } private boolean isK8s() { return System.getenv("KUBERNETES_SERVICE_HOST") != null; } private String getOutboundIp() { try (DatagramSocket socket = new DatagramSocket()) { socket.connect(InetAddress.getByName("8.8.8.8"), 10002); return socket.getLocalAddress().getHostAddress(); } catch (Exception e) { return "Unknown"; } } private List getAllNetworkIps() { List ips = new ArrayList<>(); try { Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface ni = interfaces.nextElement(); if (!ni.isUp() || ni.isLoopback()) continue; Enumeration addresses = ni.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); if (addr instanceof Inet4Address) { ips.add(addr.getHostAddress()); } } } } catch (Exception ignored) { } return ips; } private void logStructuredJson(String appName, int port, String ip, long startupMs) { log.info("STARTUP_JSON: {{\"app\":\"{}\",\"port\":{},\"ip\":\"{}\",\"startupMs\":{}}}", appName, port, ip, startupMs); } }