All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.unlogged.Runtime Maven / Gradle / Ivy

There is a newer version: 0.7.6
Show newest version
package io.unlogged;

import fi.iki.elonen.NanoHTTPD;
import io.unlogged.command.AgentCommandServer;
import io.unlogged.command.ServerMetadata;
import io.unlogged.logging.IErrorLogger;
import io.unlogged.logging.IEventLogger;
import io.unlogged.logging.Logging;
import io.unlogged.logging.SimpleFileLogger;
import io.unlogged.logging.impl.DetailedEventStreamAggregatedLogger;
import io.unlogged.logging.perthread.PerThreadBinaryFileAggregatedLogger;
import io.unlogged.logging.perthread.RawFileCollector;
import io.unlogged.logging.util.FileNameGenerator;
import io.unlogged.logging.util.NetworkClient;
import io.unlogged.util.StreamUtil;
import io.unlogged.weaver.WeaveConfig;
import io.unlogged.weaver.WeaveParameters;
import org.jetbrains.annotations.NotNull;

import java.io.*;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * This class is the main program of SELogger as a javaagent.
 */
public class Runtime {

    public static final int AGENT_SERVER_PORT = 12100;
    private static Runtime instance;
    private static List>> pendingClassRegistrations = new ArrayList<>();
    private final ScheduledExecutorService probeReaderExecutor = Executors.newSingleThreadScheduledExecutor();
    private AgentCommandServer httpServer;
    private IErrorLogger errorLogger;
    /**
     * The logger receives method calls from injected instructions via selogger.logging.Logging class.
     */
    private IEventLogger logger = Logging.initialiseDiscardLogger();
    private long lastProbesLoadTime;

    /**
     * Process command line arguments and prepare an output directory
     *
     * @param args string arguments for weaver
     */
    private Runtime(String args) {

        try {
            WeaveParameters weaveParameters = new WeaveParameters(args);

            File outputDir = new File(weaveParameters.getOutputDirname());
            if (!outputDir.exists()) {
                outputDir.mkdirs();
            }

            ServerMetadata serverMetadata =
                    new ServerMetadata(weaveParameters.getIncludedNames().toString(), Constants.AGENT_VERSION);


            if (!outputDir.isDirectory() || !outputDir.canWrite()) {
                System.err.println("[unlogged] ERROR: " + outputDir.getAbsolutePath() + " is not writable.");
                return;
            }

            WeaveConfig config = new WeaveConfig(weaveParameters);

            if (!config.isValid()) {
                System.out.println("[unlogged] no weaving option is specified.");
                return;
            }

            errorLogger = new SimpleFileLogger(outputDir);

            errorLogger.log("Java version: " + System.getProperty("java.version"));
            errorLogger.log("Agent version: " + Constants.AGENT_VERSION);
            errorLogger.log("Params: " + args);

            System.out.println("[unlogged]" +
                    " session Id: [" + config.getSessionId() + "]" +
                    " on hostname [" + NetworkClient.getHostname() + "]");

            URL probesToRecordUrl = this.getClass().getClassLoader().getResource("probes.dat");

            List probesToRecord = new ArrayList<>();
            try {

                File file = new File(probesToRecordUrl.toURI());
                lastProbesLoadTime = file.lastModified();
                probesToRecord = probeFileToIdList(file);
            } catch (Exception e) {
                // uri is not hierarchical when running a jar
                probesToRecordUrl = null;
                probesToRecord = probeFileStreamToIdList(
                        this.getClass().getClassLoader().getResourceAsStream("probes.dat"));
            }

            switch (weaveParameters.getMode()) {


                case Discard:
                    logger = Logging.initialiseDiscardLogger();

                case PerThread:

                    NetworkClient networkClient = new NetworkClient(weaveParameters.getServerAddress(),
                            config.getSessionId(), weaveParameters.getAuthToken(), errorLogger);

                    FileNameGenerator fileNameGenerator1 = new FileNameGenerator(outputDir, "index-", ".zip");
                    RawFileCollector fileCollector =
                            new RawFileCollector(weaveParameters.getFilesPerIndex(), fileNameGenerator1,
                                    networkClient, errorLogger, outputDir);

                    FileNameGenerator fileNameGenerator = new FileNameGenerator(outputDir, "log-", ".selog");
                    PerThreadBinaryFileAggregatedLogger perThreadBinaryFileAggregatedLogger
                            = new PerThreadBinaryFileAggregatedLogger(fileNameGenerator, errorLogger, fileCollector);

                    logger = Logging.initialiseAggregatedLogger(perThreadBinaryFileAggregatedLogger, outputDir);
                    break;

                case Testing:

                    NetworkClient networkClient1 =
                            new NetworkClient(weaveParameters.getServerAddress(),
                                    config.getSessionId(), weaveParameters.getAuthToken(), errorLogger);

                    FileNameGenerator archiveFileNameGenerator =
                            new FileNameGenerator(outputDir, "index-", ".zip");

                    RawFileCollector fileCollector1 =
                            new RawFileCollector(weaveParameters.getFilesPerIndex(), archiveFileNameGenerator,
                                    networkClient1, errorLogger, outputDir);

                    FileNameGenerator logFileNameGenerator =
                            new FileNameGenerator(outputDir, "log-", ".selog");

                    PerThreadBinaryFileAggregatedLogger perThreadBinaryFileAggregatedLogger1
                            = new PerThreadBinaryFileAggregatedLogger(logFileNameGenerator, errorLogger,
                            fileCollector1);

                    logger = Logging.initialiseDetailedAggregatedLogger(perThreadBinaryFileAggregatedLogger1,
                            outputDir, probesToRecord);

                    DetailedEventStreamAggregatedLogger detailedLogger = (DetailedEventStreamAggregatedLogger) logger;
                    if (probesToRecordUrl != null) {
                        URL finalProbesToRecordUrl = probesToRecordUrl;
                        probeReaderExecutor.scheduleWithFixedDelay(
                                () -> {
                                    try {
                                        File probesFile = new File(finalProbesToRecordUrl.toURI());
                                        if (!probesFile.exists()) {
                                            return;
                                        }
                                        long newProbesFileModifiedTime = probesFile.lastModified();
                                        if (newProbesFileModifiedTime > lastProbesLoadTime) {
                                            lastProbesLoadTime = newProbesFileModifiedTime;
                                            List newProbeIdList = probeFileToIdList(probesFile);
                                            detailedLogger.setProbesToRecord(newProbeIdList);
                                        }
                                    } catch (URISyntaxException | IOException e) {
                                        // should never happen
                                    }
                                }, 1000, 300, TimeUnit.MILLISECONDS
                        );
                    }
                    break;

            }

            httpServer = new AgentCommandServer(AGENT_SERVER_PORT, serverMetadata);
            httpServer.setAgentCommandExecutor(new AgentCommandExecutorImpl(logger.getObjectMapper(), logger));
            httpServer.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);

            java.lang.Runtime.getRuntime()
                    .addShutdownHook(new Thread(() -> {
                        close();
                    }));


        } catch (Throwable thx) {
            thx.printStackTrace();
            System.err.println(
                    "[unlogged] agent init failed, this session will not be recorded => " + thx.getMessage());
        }
    }

    public static Runtime getInstance(String args) {
        if (instance != null) {
            return instance;
        }
        synchronized (Runtime.class) {
            if (instance != null) {
                return instance;
            }

            try {
                StackTraceElement callerClassAndMethodStack = new Exception().getStackTrace()[1];
                Class callerClass = Class.forName(callerClassAndMethodStack.getClassName());
                for (Method method : callerClass.getMethods()) {
                    if (method.getAnnotation(Unlogged.class) != null) {
                        // caller method
                        Unlogged annotationData = method.getAnnotation(Unlogged.class);
                        if (!annotationData.enable()) {
                            return null;
                        }
                        break;
                    }
                }

            } catch (ClassNotFoundException e) {
                // should never happen
                // disable if happened
                return null;
            }
            instance = new Runtime(args);
//            for (Pair> pendingClassRegistration : pendingClassRegistrations) {
//                registerClass(pendingClassRegistration.getFirst(), pendingClassRegistration.getSecond());
//            }

        }
        return instance;
    }

    @NotNull
    private List probeFileToIdList(File file) throws IOException {
        InputStream probesFile = this.getClass().getClassLoader().getResourceAsStream(file.getName());
        return probeFileStreamToIdList(probesFile);
    }

    @NotNull
    private List probeFileStreamToIdList(InputStream probesFile) throws IOException {
        List probesToRecord = new ArrayList<>();
        if (probesFile == null) {
            return probesToRecord;
        }
        byte[] probeToRecordBytes = StreamUtil.streamToBytes(probesFile);
        DataInputStream dis = new DataInputStream(new ByteArrayInputStream(probeToRecordBytes));
        try {
            while (true) {
                int probeId = dis.readInt();
                probesToRecord.add(probeId);
            }
        } catch (EOFException e) {

        }
        return probesToRecord;
    }

//    // this method is called by all classes which were probed during compilation time
//    public static boolean registerClass(String classInfoBytes, List probeIdsToRecord) {
//        if (instance != null) {
//            byte[] decodedBytes = Base64.getDecoder().decode(classInfoBytes);
//            ClassInfo classInfo = new ClassInfo();
//
//            try {
//                ByteArrayInputStream in = new ByteArrayInputStream(decodedBytes);
//                classInfo.readFromDataStream(in);
//            } catch (IOException e) {
////            throw new RuntimeException(e);
//                return false;
//            }
//
//            instance.logger.recordWeaveInfo(decodedBytes, classInfo, probeIdsToRecord);
//
//        } else {
//
//            pendingClassRegistrations.add(new Pair<>(classInfoBytes, probeIdsToRecord));
//        }
//        return true;
//    }

    /**
     * Close data streams if necessary
     */
    public void close() {
        if (logger != null) {
            logger.close();
        }
        if (httpServer != null) {
            httpServer.stop();

        }
        if (errorLogger != null) {
            errorLogger.close();
        }
        System.out.println("[unlogged] shutdown complete");

    }

    public enum Mode {Stream, Frequency, FixedSize, Discard, Network, PerThread, Testing}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy