/* * Copyright 2015 the original author or authors. * @https://github.com/scouter-project/scouter * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package scouter.client.views; import java.io.File; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IViewSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.ViewPart; import scouter.client.Images; import scouter.client.model.TextProxy; import scouter.client.net.TcpProxy; import scouter.client.stack.actions.FetchSingleStackJob; import scouter.client.stack.base.MainProcessor; import scouter.client.util.ColoringWord; import scouter.client.util.ConsoleProxy; import scouter.client.util.CustomLineStyleListener; import scouter.client.util.ExUtil; import scouter.client.util.ImageUtil; import scouter.client.util.TimeUtil; import scouter.client.util.UIUtil; import scouter.lang.pack.MapPack; import scouter.lang.value.ListValue; import scouter.net.RequestCmd; import scouter.util.CastUtil; import scouter.util.DateUtil; import scouter.util.StringUtil; public class ObjectThreadDumpView extends ViewPart { public final static String ID = ObjectThreadDumpView.class.getName(); private ArrayList<ColoringWord> defaultHighlightings; private StyledText text; private String objName; private int objHash; private int serverId; private boolean isTable = true; private Table table; private String indexFilename = null; public void init(IViewSite site) throws PartInitException { super.init(site); String secondId = site.getSecondaryId(); if (secondId != null) { String[] tokens = StringUtil.tokenizer(secondId, "&"); this.objHash = CastUtil.cint(tokens[0]); this.isTable = false; } initializeColoring(); } public void initializeColoring(){ defaultHighlightings = new ArrayList<ColoringWord>(); defaultHighlightings.add(new ColoringWord("java.lang.Thread.State:", SWT.COLOR_BLUE, false)); defaultHighlightings.add(new ColoringWord("Object.wait()", SWT.COLOR_BLUE, false)); defaultHighlightings.add(new ColoringWord("daemon", SWT.COLOR_BLUE, false)); defaultHighlightings.add(new ColoringWord("java.util", SWT.COLOR_BLUE, false)); defaultHighlightings.add(new ColoringWord("prio", SWT.COLOR_BLUE, false)); defaultHighlightings.add(new ColoringWord("org.apache", SWT.COLOR_BLUE, false)); defaultHighlightings.add(new ColoringWord("locked", SWT.COLOR_RED, false)); defaultHighlightings.add(new ColoringWord("java.lang.Thread.run", SWT.COLOR_DARK_GREEN, false)); defaultHighlightings.add(new ColoringWord("java.lang", SWT.COLOR_DARK_MAGENTA, false)); defaultHighlightings.add(new ColoringWord("waiting on", SWT.COLOR_DARK_RED, false)); } Composite headerComp; Button findButton, analyzeBtn; Text searchText; public void createUpperMenu(Composite composite){ headerComp = new Composite(composite, SWT.NONE); headerComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); headerComp.setLayout(UIUtil.formLayout(0, 0)); analyzeBtn = new Button(headerComp, SWT.PUSH); analyzeBtn.setLayoutData(UIUtil.formData(null, -1, 0, 2, 100, -5, null, -1)); analyzeBtn.setText("SFA"); analyzeBtn.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.Selection: MainProcessor.instance().processStackContents(text.getText()); break; } } }); findButton = new Button(headerComp, SWT.PUSH); findButton.setLayoutData(UIUtil.formData(null, -1, 0, 2, analyzeBtn, -3, null, -1)); findButton.setText("Find"); findButton.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.Selection: listener.setSearchString(searchText.getText()); text.redraw(); } } }); searchText = new Text(headerComp, SWT.BORDER); searchText.setLayoutData(UIUtil.formData(null, -1, 0, 5, findButton, -5, null, -1, 300)); searchText.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { if(e.keyCode == 13){ // enter key listener.setSearchString(searchText.getText()); text.redraw(); } } public void keyReleased(KeyEvent e) {} }); } Shell shell; boolean loaded = false; CustomLineStyleListener listener; public void createPartControl(final Composite parent) { shell = parent.getShell(); parent.addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { } public void keyPressed(KeyEvent e) { } }); Composite composite = new Composite(parent, SWT.NONE); GridLayout gLayout = new GridLayout(1, true); gLayout.horizontalSpacing = 0; gLayout.marginHeight = 0; gLayout.marginWidth = 0; composite.setLayout(gLayout); createUpperMenu(composite); Composite textComposite = new Composite(composite, SWT.NONE); textComposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true)); textComposite.setLayout(new FillLayout()); SashForm sashHoriForm = null; if(isTable){ sashHoriForm = new SashForm(textComposite, SWT.HORIZONTAL); sashHoriForm.SASH_WIDTH = 3; Composite tableComposite = new Composite(sashHoriForm, SWT.NONE); table = new Table(tableComposite, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.FULL_SELECTION); table.setLinesVisible(true); table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); table.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { TableItem[] items = table.getSelection(); if (items != null && items.length > 0) { TableItem first = items[0]; TableItem last = items[items.length - 1]; } } public void widgetDefaultSelected(SelectionEvent e) {} }); table.addMouseListener(new MouseListener(){ public void mouseDoubleClick(MouseEvent e) { } public void mouseDown(MouseEvent e) { } public void mouseUp(MouseEvent e) { TableItem[] items = table.getSelection(); if(items == null){ return; } if(serverId != 0){ long from = (Long) items[0].getData(); new FetchSingleStackJob(serverId, objName, from, null, ObjectThreadDumpView.this).schedule(500); }else{ loadBatchStackContents((Long) items[0].getData(), Integer.parseInt(items[0].getText())); } } }); TableColumn indexColumn = new TableColumn(table, SWT.NONE); TableColumn timeColumn = new TableColumn(table, SWT.NONE); TableColumnLayout tableColumnLayout = new TableColumnLayout(); tableColumnLayout.setColumnData(indexColumn, new ColumnWeightData(20)); tableColumnLayout.setColumnData(timeColumn, new ColumnWeightData(80)); tableComposite.setLayout(tableColumnLayout); text = new StyledText(sashHoriForm, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); }else{ text = new StyledText(textComposite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); } text.addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { } public void keyPressed(KeyEvent e) { if(e.stateMask == SWT.CTRL){ if(e.keyCode == 'a'){ text.selectAll(); }else if(e.keyCode == 'f'){ searchText.setFocus(); searchText.selectAll(); } } } }); listener = new CustomLineStyleListener(false, defaultHighlightings, false, true, SWT.COLOR_YELLOW); text.addLineStyleListener(listener); IToolBarManager man = getViewSite().getActionBars().getToolBarManager(); man.add(new Action("Copy", ImageUtil.getImageDescriptor(Images.copy)) { public void run() { Clipboard clipboard = new Clipboard(Display.getDefault()); clipboard.setContents(new Object[] { text.getText() }, new Transfer[] { TextTransfer.getInstance() }); clipboard.dispose(); MessageDialog.openInformation(parent.getShell(), "Copied", "Copy all contents to clipboard"); } }); if(sashHoriForm != null){ sashHoriForm.setWeights(new int [] {10, 40}); } } public void setInput(int serverId){ this.serverId = serverId; this.setPartName("ThreadDump[" + TextProxy.object.getLoadText(DateUtil.yyyymmdd(TimeUtil.getCurrentTime(serverId)), objHash, serverId) + "]"); load(); } public void setInput(String stackText){ text.setText(stackText); } public void setInput(String stackText, String objName, int serverId, long stackTime, List<Long> list){ this.setPartName("ThreadDump[" + objName + " " + DateUtil.yyyymmdd(stackTime) + "]"); this.objName = objName; this.serverId = serverId; text.setText(stackText); loadAgentStackList(list); } public void setInput(String objName, String filename, List<Long> [] lists){ this.setPartName("ThreadDump[" + objName + " " + DateUtil.yyyymmdd(lists[0].get(0)) + "]"); this.objName = objName; this.indexFilename = filename; loadBatchStackList(lists); if(lists != null){ if(lists[1].size() == 1){ loadThreadDump(0, 0); }else{ loadThreadDump(0, ((Long)lists[1].get(1)).intValue()); } } } public void load() { ExUtil.asyncRun(new Runnable() { public void run() { MapPack mpack = null; TcpProxy tcp = TcpProxy.getTcpProxy(serverId); try { MapPack param = new MapPack(); param.put("objHash", objHash); mpack = (MapPack) tcp.getSingle(RequestCmd.OBJECT_THREAD_DUMP, param); } catch(Exception e){ ConsoleProxy.errorSafe(e.toString()); } finally { TcpProxy.putTcpProxy(tcp); } if (mpack != null) { String error = mpack.getText("error"); if (error != null) { ConsoleProxy.errorSafe(error); } final ListValue lv = mpack.getList("threadDump"); ExUtil.exec(text, new Runnable() { public void run() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < lv.size(); i++) { sb.append(lv.getString(i) + "\n"); } text.setText(sb.toString()); } }); } } }); } private void loadAgentStackList(final List<Long> list){ if(list == null){ return; } ExUtil.exec(table, new Runnable() { public void run() { long value; for (int i = 0 ; i < list.size(); i++) { value = list.get(i); TableItem item = new TableItem(table, SWT.NONE); item.setText(0, String.valueOf(i+1)); item.setText(1, DateUtil.format(value, "yyyy-MM-dd HH:mm:ss")); item.setData(value); } } }); } private void loadBatchStackList(final List<Long> [] lists){ if(lists == null){ return; } ExUtil.exec(table, new Runnable() { public void run() { List<Long> time = lists[0]; List<Long> position = lists[1]; for (int i = 0 ; i < time.size(); i++) { TableItem item = new TableItem(table, SWT.NONE); item.setText(0, String.valueOf(i+1)); item.setText(1, DateUtil.format(time.get(i), "yyyy-MM-dd HH:mm:ss")); item.setData(position.get(i)); } } }); } public void setFocus() { } private void loadThreadDump(long position, int length){ File stackFile = null; if(this.indexFilename == null){ return; }else{ stackFile = new File(this.indexFilename.substring(0, this.indexFilename.length() - 4) + ".log"); } String contents = ""; RandomAccessFile afr = null; try { if(length == 0){ length = (int)(stackFile.length() - position); } afr = new RandomAccessFile(stackFile, "r"); afr.seek(position); byte [] buffer = new byte[length]; int totalSize= 0; int readSize; while((readSize = afr.read(buffer, totalSize, length-totalSize)) > 0){ totalSize += readSize; if(totalSize >= length){ break; } } contents = new String(buffer, "UTF-8"); }catch(Exception ex){ ex.printStackTrace(); }finally{ if(afr != null){ try {afr.close(); }catch(Exception ex){} } } text.setText(contents); } private void loadBatchStackContents(long position, int index){ TableItem item = null; if(index < table.getItemCount()){ item = table.getItem(index); } int length = 0; if(item != null){ length = ((Long)item.getData()).intValue(); length = (int)(length - position); } loadThreadDump(position, length); } }