Catching All Log Messages

Discussion in 'Plugin Development' started by meguy26, Jul 4, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    meguy26

    So, to test my skill in java I am developing a remote console plugin, similar to CloudConsole or BukkitRemote. I am having a problem with capturing all of the logs and/or prints sent to the regular console. I am using the following code to apply filters:
    Code:
    /**
    *
    */
    package com.gmail.neonblue858.remoteconsole.plugin;
    
    import java.util.Enumeration;
    import java.util.logging.LogManager;
    import java.util.logging.Logger;
    
    import org.bukkit.Bukkit;
    import org.bukkit.plugin.Plugin;
    import org.bukkit.scheduler.BukkitRunnable;
    
    /**
    *
    *
    *@author Meguy26
    *
    */
    public class FilterApplyer extends BukkitRunnable {
        private ClientManager man;
       
        public FilterApplyer(ClientManager man){
            this.man = man;
        }
       
        /* (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run() {
            Enumeration<String> str = LogManager.getLogManager().getLoggerNames();
            while(str.hasMoreElements()){
                String ele = str.nextElement();
                Logger log = LogManager.getLogManager().getLogger(ele);
                log.setFilter(new LogFilter(man));
            }
           
            for(Plugin p : Bukkit.getPluginManager().getPlugins()){
                p.getLogger().setFilter(new LogFilter(man));
            }
           
            Bukkit.getLogger().setFilter(new LogFilter(man));
           
            System.setOut(new FilterOutputStream(System.out, man));
            System.setErr(new FilterOutputStream(System.err, man));
        }
    
    }
    
    LogFilter and FilterOutputStream are just some of my classes, and they work fine. The problem is I am not applying the filter to everything... For example, when the command "/say hi" is executed in the console, the message "[Server] hi" appears in the regular console, but is not caught by the code above. Is there some way to apply a filter directly to the console itself?
     
  2. Offline

    mythbusterma

    @meguy26

    That's because Bukkit's Logger and your plugin's Logger are two separate instances, i.e. Bukkit.getLogger() and JavaPlugin#getLogger() do not return the same Logger object.
     
  3. Offline

    meguy26

    @mythbusterma
    I'm confused by your answer... I know that each plugin has its own logger, and so does bukkit, the problem I have is that I cannot seem to access every single logger with my code, so that i can apply my filter. What I need to do is capture all the text sent to the normal server console, and send it of to my remote console client. The sending, and capturing is mostly working, but for whatever reason I cannot capture all the text sent to the console such as:
     
  4. Offline

    mythbusterma

    @meguy26

    Ah, never mind, I missed the part where you added the filter to all the plugins as well, I thought you only added it to Bukkit's, my mistake.

    I'm not familiar with logging filters, the way this is usually done (in Java and most other languages) is by adding a "handler" to the loggers. Try using that and setting the logging level of the Handler to "INFO."
     
  5. Offline

    meguy26

    @mythbusterma
    My logger "handlers" are working fine, I successfully apply a filter, or "handler" to most of the loggers, the problem I am having is that my code, for whatever reason, does not apply filters to everything coming into the console, such as:
    I must be communicating something wrong, @mythbusterma is a great forum helper... Please ask any questions you have and i will clarify.
     
    Last edited: Jul 4, 2015
  6. Offline

    Tecno_Wizard

    @meguy26, I think I get it. You're trying to fetch EVERY message sent to the log regardless of it's source. I was actually digging through another plugin's code trying to learn how it uses IMAP and POP for email notifications. I saw this thread and recalled that it had a class that did this. Now I'm not great with logs, but you may be able to reverse engineer this class.

    Code:
    package com.codisimus.plugins.textplayer;
    
    import java.util.logging.Handler;
    import java.util.logging.Level;
    import java.util.logging.LogRecord;
    
    public class LogListener
      extends Handler
    {
      static final int ANTI_SPAM_TIMER = 600000;
      static long antiSpamClock;
    
      public void publish(LogRecord record)
      {
        if (record.getLevel() != Level.SEVERE) {
          return;
        }
        long time = System.currentTimeMillis();
        if (time < antiSpamClock) {
          return;
        }
        String msg = record.getMessage();
        if (msg == null) {
          return;
        }
        for (User user : TextPlayer.getUsers()) {
          if (user.watchingErrors) {
            user.sendText(record.getLoggerName() + " generated an error", msg);
          }
        }
        antiSpamClock = time + 600000L;
      }
    
      public void flush() {}
    
      public void close()
        throws SecurityException
      {}
    }
    
    Sorry if this is useless. I have no idea how this works.
     
  7. Offline

    mythbusterma

    @meguy26

    Again, my recommendation is try and use Handlers rather than Filters. The Handler can capture all messages, the Filter will only apply to existing Handlers (if I recall correctly).
     
  8. Offline

    meguy26

    @mythbusterma
    Changing to a handler did improve some logging, however it still does not catch everything, such as player joins, and command executions/results, including the example ive quoted too many times already.
     
  9. Offline

    mythbusterma

    @meguy26

    Again, make sure that you change the Logging level of your Handler to handle LogLevel.INFO, as the messages you describe are probably INFO messages, and the default is WARN.
     
  10. Offline

    meguy26

    @mythbusterma
    Ok, I updated my code, and fixed an issue in my FilterOutputStream class, but still it refuses to catch player joins, command results, or player chats.

    Code:
    Code:
    /**
    *
    */
    package com.gmail.neonblue858.remoteconsole.plugin;
    
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    import org.bukkit.scheduler.BukkitRunnable;
    
    /**
    *
    *
    *@author Meguy26
    *
    */
    public class FilterApplyer extends BukkitRunnable {
        private ClientManager man;
       
        public FilterApplyer(ClientManager man){
            this.man = man;
        }
       
        /* (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run() {
            //Create handler
            LogHandler handler = new LogHandler(man);
            //Set handler to capture everything
            handler.setLevel(Level.ALL);
            //Add handler to root logger so it applies to all loggers
            Logger.getLogger("").addHandler(handler);
           
            //Set the system out to a filtering output stream
            System.setOut(new FilterOutputStream(System.out, man));
           
            //Set the system err to a filtering output stream
            System.setErr(new FilterOutputStream(System.err, man));
           
        }
    
    }
    
    LogHandler:
    Code:
    /**
    *
    */
    package com.gmail.neonblue858.remoteconsole.plugin;
    
    import java.util.logging.Handler;
    import java.util.logging.LogRecord;
    
    /**
    *
    *
    *@author Meguy26
    *
    */
    public class LogHandler extends Handler {
        private ClientManager man;
       
        public LogHandler(ClientManager man){
            this.man = man;
        }
       
        /* (non-Javadoc)
         * @see java.util.logging.Handler#close()
         */
        @Override
        public void close() throws SecurityException {
        }
    
        /* (non-Javadoc)
         * @see java.util.logging.Handler#flush()
         */
        @Override
        public void flush() {
        }
    
        /* (non-Javadoc)
         * @see java.util.logging.Handler#publish(java.util.logging.LogRecord)
         */
        @Override
        public void publish(LogRecord ev) {
            this.man.print(ev);
        }
    
    }
    
    FilterOutputStream:

    Code:
    /**
    *
    */
    package com.gmail.neonblue858.remoteconsole.plugin;
    
    import java.io.OutputStream;
    
    import com.gmail.neonblue858.remoteconsole.api.MOutputStream;
    
    /**
    *
    *
    * @author Meguy26
    *
    */
    public class FilterOutputStream extends MOutputStream {
        ClientManager man;
    
        /**
         * @param out
         *
         * @author Meguy26
         */
        public FilterOutputStream(OutputStream out, ClientManager man) {
            super(out);
            this.man = man;
        }
    
        /*
         * (non-Javadoc)
         *
         * @see
         * com.gmail.neonblue858.remoteconsole.api.MOutputStream#filter(java.lang.
         * String)
         */
        @Override
        protected void filter(String s) {
            if (!s.equals("\n") && !s.equals("\r\n")) {
                man.print(s.replaceAll("\u001B\\[[;\\d]*[ -/]*[@-~]", ""), "System");
            }
        }
    
    }
    
    MOutputStream:

    Code:
    package com.gmail.neonblue858.remoteconsole.api;
    
    import java.io.OutputStream;
    import java.io.PrintStream;
    
    public abstract class MOutputStream extends PrintStream {
    
        public MOutputStream(OutputStream out) {
            super(out);
        }
    
        private void internalFilter(String toFilter, boolean println) {
            if (println) {
                this.filter(System.lineSeparator());
            } else {
                this.filter(toFilter);
            }
        }
    
        @Override
        public void print(String s) {
            super.print(s);
            this.internalFilter(s, false);
        }
    
        @Override
        public void print(int s) {
            super.print(s);
            this.internalFilter(String.valueOf(s), false);
        }
    
        @Override
        public void print(long s) {
            super.print(s);
            this.internalFilter(String.valueOf(s), false);
        }
    
        @Override
        public void print(float s) {
            super.print(s);
            this.internalFilter(String.valueOf(s), false);
        }
    
        @Override
        public void print(char s) {
            super.print(s);
            this.internalFilter(String.valueOf(s), false);
        }
    
        @Override
        public void print(double s) {
            super.print(s);
            this.internalFilter(String.valueOf(s), false);
        }
    
        @Override
        public void print(char[] s) {
            super.print(s);
            this.internalFilter(String.valueOf(s), false);
        }
    
        @Override
        public void print(Object x) {
            super.print(x);
            this.internalFilter(String.valueOf(x), false);
        }
    
        @Override
        public void println(String s) {
            super.println(s);
            this.internalFilter(String.valueOf(s), true);
        }
    
        @Override
        public void println(int s) {
            super.println(s);
            this.internalFilter(String.valueOf(s), true);
        }
    
        @Override
        public void println(long s) {
            super.println(s);
            this.internalFilter(String.valueOf(s), true);
        }
    
        @Override
        public void println(float s) {
            super.println(s);
            this.internalFilter(String.valueOf(s), true);
        }
    
        @Override
        public void println(char s) {
            super.println(s);
            this.internalFilter(String.valueOf(s), true);
        }
    
        @Override
        public void println(double s) {
            super.println(s);
            this.internalFilter(String.valueOf(s), true);
        }
    
        @Override
        public void println(char[] s) {
            super.println(s);
            this.internalFilter(String.valueOf(s), true);
        }
    
        @Override
        public void println(Object x) {
            super.println(x);
            this.internalFilter(String.valueOf(x), true);
        }
    
        protected abstract void filter(String s);
    
        /**
         * Counts the amount of times each character occurs.
         *
         * @param input
         *            - The String to read.
         * @param possibilites
         *            - The characters to count.
         * @return The number of characters found.
         */
        public int countChars(String input, char[] possibilites) {
            int count = 0;
            for (int i = 0; i < input.length(); i++) {
                for (int z = 0; z < possibilites.length; z++) {
                    if (input.charAt(i) == possibilites[z]) {
                        count++;
                    }
                }
            }
            return count;
        }
    
        /**
         * Gets the string between two characters.
         *
         * @param input
         *            - The String to read.
         * @param from
         *            - The character to start recording from.
         * @param to
         *            - The character to stop recording at.
         * @return The string between the specified characters.
         */
        public String getFromTo(String input, char from, char to) {
            String toReturn = "";
            boolean recording = false;
            boolean processed = false;
            for (int i = 0; i < input.length(); i++) {
                String targ = String.valueOf(input.charAt(i));
                if (recording) {
                    processed = true;
                    toReturn = toReturn + targ;
                }
                if (targ.equals(String.valueOf(from)) && !recording) {
                    recording = true;
                } else if (targ.equals(String.valueOf(to)) && recording) {
                    recording = false;
                    toReturn = toReturn.substring(0, toReturn.length() - 1);
                    break;
                }
            }
            if (!processed) {
                return null;
            } else {
                return toReturn;
            }
        }
    
        /**
         * Counts the amount of times each character occurs.
         *
         * @param input
         *            - The String to read.
         * @param poss
         *            - The character to count.
         * @return The number of characters found.
         */
        public int countChars(String input, char poss) {
            char[] p = { poss };
            return this.countChars(input, p);
        }
    
        /**
         * Checks if the specified characters appear in a string in the specified
         * order, even if there are other characters between them. For example
         * {@code charsAppearInOrder("(foo)",'(',')')} will return true whereas
         * {@code charsAppearInOrder("]foo[",'[',']')} would return false.
         *
         * @param input
         * @param chars
         * @return
         */
        public boolean charsAppearInOrder(String input, char... chars) {
            if (input.length() < chars.length) {
                return false;
            } else {
    
                int c = 0;
                for (int i = 0; i < input.length(); i++) {
                    char one = input.charAt(i);
                    char two = chars[c];
                    if (one == two) {
                        c++;
                    }
                    if (c >= chars.length) {
                        break;
                    }
                }
    
                if (c == chars.length) {
                    return true;
                } else {
                    return false;
                }
            }
        }
    
    }
     
Thread Status:
Not open for further replies.

Share This Page