Package lcmc.common.ui

Source Code of lcmc.common.ui.Logs

/*
* This file is part of DRBD Management Console by LINBIT HA-Solutions GmbH
* written by Rasto Levrinc.
*
* Copyright (C) 2009, LINBIT HA-Solutions GmbH.
* Copyright (C) 2011-2012, Rastislav Levrinc.
*
* DRBD Management Console is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* DRBD Management Console is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with drbd; see the file COPYING.  If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/


package lcmc.common.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Named;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import lcmc.cluster.ui.widget.WidgetFactory;
import lcmc.common.domain.Application;
import lcmc.host.domain.Host;
import lcmc.common.domain.ExecCallback;
import lcmc.logger.Logger;
import lcmc.logger.LoggerFactory;
import lcmc.common.ui.utils.MyButton;
import lcmc.common.domain.util.Tools;
import lcmc.cluster.service.ssh.ExecCommandConfig;

/**
* An implementation of an dialog with log files from many hosts.
*/
@Named
public class Logs extends ConfigDialog {
    private static final Logger LOG = LoggerFactory.getLogger(Logs.class);
    private final JTextPane logTextArea = new JTextPane();
    private final Map<String, JCheckBox> patternToCheckBoxMap = new HashMap<String, JCheckBox>();
    private final Lock mRefreshLock = new ReentrantLock();
    private final Collection<JComponent> additionalComponents = new ArrayList<JComponent>();
    @Inject
    private Application application;
    @Inject
    private WidgetFactory widgetFactory;

    /**
     * Command that gets the log. The command must be specified in the
     * DistResource or some such.
     */
    protected String logFileCommand() {
        return "Logs.hbLog";
    }

    protected final String grepPattern() {
        final StringBuilder pattern = new StringBuilder(40);
        pattern.append('\'');
        final Map<String, String> patternMap = getPatternMap();
        boolean first = true;
        for (final Map.Entry<String, String> patternEntry : patternMap.entrySet()) {
            if (patternToCheckBoxMap.get(patternEntry.getKey()).isSelected()) {
                if (!first) {
                    pattern.append(".*");
                }
                pattern.append(patternEntry.getValue());
                first = false;
            }
        }
        pattern.append('\'');
        return pattern.toString();
    }

    @Override
    protected final void initDialogBeforeVisible() {
        super.initDialogBeforeVisible();
        enableAllComponents(false);
        refreshLogsThread();
    }

    protected void refreshLogsThread() {
        final Thread thread = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    if (!mRefreshLock.tryLock()) {
                        return;
                    }
                    try {
                        refreshLogs();
                    } finally {
                        mRefreshLock.unlock();
                    }
                }
            });
        thread.start();
    }

    protected Host[] getHosts() {
        return new Host[]{};
    }

    protected void enableAllComponents(final boolean enable) {
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                for (final Map.Entry<String, JCheckBox> checkBoxEntry : patternToCheckBoxMap.entrySet()) {
                    checkBoxEntry.getValue().setEnabled(enable);
                }
                for (final JComponent ac : additionalComponents) {
                    ac.setEnabled(enable);
                }
            }
        });
    }

    protected Map<String, String> getOptionsHash() {
        final Map<String, String> replaceHash = new HashMap<String, String>();
        replaceHash.put("@GREPPATTERN@", grepPattern());
        return replaceHash;
    }

    /**
     * Gets logs from specified command (logFileCommand) and grep pattern
     * (grepPatter). It also mixes the log files from all the nodes, sorts
     * them, and assigns colors for lines from different hosts.
     */
    protected final void refreshLogs() {
        enableAllComponents(false);
        final Host[] hosts = getHosts();
        final Thread[] threads = new Thread[hosts.length];
        final String[] texts = new String[hosts.length];

        final Map<String, String> replaceHash = getOptionsHash();

        int i = 0;
        final String stacktrace = Tools.getStackTrace();
        for (final Host host : hosts) {
            final int index = i;
            final String command = host.getDistCommand(logFileCommand(), replaceHash);
            threads[index] = host.execCommand(new ExecCommandConfig()
                                                   .command(command)
                                                   .execCallback(new ExecCallback() {
                                                       @Override
                                                       public void done(final String answer) {
                                                           texts[index] = answer;
                                                       }
                                                       @Override
                                                       public void doneError(final String answer,
                                                                             final int errorCode) {
                                                           texts[index] = host.getName() + ": " + answer + '\n';
                                                           LOG.sshError(host, command, answer, stacktrace, errorCode);
                                                       }
                                                   })
                                                   .sshCommandTimeout(30000)
                                                   .silentCommand()
                                                   .silentOutput());
            i++;
        }
        i = 0;
        final StringBuilder ans = new StringBuilder("");
        for (final Thread t : threads) {
            try {
                t.join();
            } catch (final InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            ans.append(texts[i]);
            i++;
        }
        final String[] output = ans.toString().split("\r\n");
        final String[] months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
        final Pattern p = Pattern.compile('(' + Tools.join("|", months) + ") +(\\d+) +(\\d+):(\\d+):(\\d+).*");
        final Map<String, Integer> monthsHash = new HashMap<String, Integer>();
        i = 0;
        for (final String m : months) {
            monthsHash.put(m, i);
            i++;
        }
        Arrays.sort(output,
                    new Comparator<String>() {
                        @Override
                        public int compare(final String o1, final String o2) {
                            final Matcher m1 = p.matcher(o1);
                            final Matcher m2 = p.matcher(o2);
                            if (m1.matches() && m2.matches()) {
                                final int month1 = monthsHash.get(m1.group(1));
                                final int month2 = monthsHash.get(m2.group(1));

                                final int day1 = Integer.valueOf(m1.group(2));
                                final int day2 = Integer.valueOf(m2.group(2));

                                final int hour1 = Integer.valueOf(m1.group(3));
                                final int hour2 = Integer.valueOf(m2.group(3));

                                final int min1 = Integer.valueOf(m1.group(4));
                                final int min2 = Integer.valueOf(m2.group(4));

                                final int sec1 = Integer.valueOf(m1.group(5));
                                final int sec2 = Integer.valueOf(m2.group(5));

                                if (month1 != month2) {
                                    return month1 < month2 ? -1 : 1;
                                }
                                if (day1 != day2) {
                                    return day1 < day2 ? -1 : 1;
                                }
                                if (hour1 != hour2) {
                                    return hour1 < hour2 ? -1 : 1;
                                }
                                if (min1 != min2) {
                                    return min1 < min2 ? -1 : 1;
                                }
                                if (sec1 != sec2) {
                                    return sec1 < sec2 ? -1 : 1;
                                }
                            }
                            return 0;
                        }
                    }
                   );
        logTextArea.setText("");
        final Document doc = logTextArea.getStyledDocument();
        final SimpleAttributeSet color1 = new SimpleAttributeSet();
        final SimpleAttributeSet color2 = new SimpleAttributeSet();
        StyleConstants.setForeground(color1, Color.BLACK);
        StyleConstants.setForeground(color2, Color.BLUE);
        SimpleAttributeSet color = null;
        int start = 0;
        int a = 0;
        String prevHost = "";
        for (final String line : output) {
            final String[] tok = line.split("\\s+");
            if (tok.length > 3) {
                final String host = tok[3];
                if (!host.equals(prevHost)) {
                    if (a == 0) {
                        a++;
                        color = color1;
                    } else {
                        a--;
                        color = color2;
                    }
                }
                prevHost = host;
            }
            final SimpleAttributeSet color0 = color;
            final int start0 = start;
            try {
                doc.insertString(start0, line + '\n', color0);
            } catch (final BadLocationException e) {
                LOG.appError("refreshLogs: could not insert line", e);
            }

            logTextArea.setCaretPosition(logTextArea.getDocument().getLength());
            start += line.length() + 1;
        }

        enableComponents();
        enableAllComponents(true);
    }

    @Override
    protected String getDialogTitle() {
        return Tools.getString("Dialog.ClusterLogs.Title");
    }

    @Override
    protected String getDescription() {
        return "";
    }

    protected final String wordBoundary(final String w) {
        return "\\\\<" + w + "\\\\>";
    }

    /** Returns a map from pattern name to its pattern. */
    protected Map<String, String> getPatternMap() {
        return new LinkedHashMap<String, String>();
    }

    /** Returns which pattern names are selected by default. */
    protected Set<String> getSelectedSet() {
        return new HashSet<String>();
    }

    /** Returns panel with checkboxes. */
    private JPanel getGrepChoicesPane() {
        final JPanel pane = new JPanel(new FlowLayout(FlowLayout.LEADING));
        pane.setBackground(Tools.getDefaultColor("ConfigDialog.Background.Dark"));
        final Map<String, String> patternMap = getPatternMap();
        for (final String name : patternMap.keySet()) {
            final JCheckBox cb = new JCheckBox(name, getSelectedSet().contains(name));
            cb.setBackground(Tools.getDefaultColor("ConfigDialog.Background.Dark"));
            patternToCheckBoxMap.put(name, cb);
            cb.addItemListener(new ItemListener() {
                @Override
                public void itemStateChanged(final ItemEvent e) {
                    refreshLogsThread();
                }
            });
            pane.add(cb);
        }
        for (final JComponent ac : getAdditionalComponents()) {
            additionalComponents.add(ac);
            pane.add(ac);
        }
        return pane;
    }

    protected MyButton getRefreshBtn() {
        final MyButton refreshBtn = widgetFactory.createButton(Tools.getString("Dialog.Logs.RefreshButton"));
        refreshBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent e) {
                refreshLogsThread();
            }
        });
        return refreshBtn;
    }

    protected JComponent[] getAdditionalComponents() {
        return new JComponent[]{getRefreshBtn()};
    }

    @Override
    protected final JComponent getInputPane() {
        final JPanel pane = new JPanel();
        pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
        pane.setBackground(Tools.getDefaultColor("ConfigDialog.Background.Dark"));
        logTextArea.setEditable(false);
        logTextArea.setText("loading...");
        pane.add(getGrepChoicesPane());
        final JScrollPane sp = new JScrollPane(logTextArea);
        sp.setPreferredSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
        pane.add(sp);
        pane.setMaximumSize(new Dimension(Short.MAX_VALUE, pane.getPreferredSize().height));
        return pane;
    }

    @Override
    protected final ImageIcon icon() {
        return Info.LOGFILE_ICON;
    }
}
TOP

Related Classes of lcmc.common.ui.Logs

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.