From: ho.namkoong Date: Thu, 11 Apr 2013 10:59:00 +0000 (+0900) Subject: [Title] Add logger X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ced8dd1fe9ea2dcc52edd999731b5f23ad2ec005;p=sdk%2Fide%2Fcommon-eplugin.git [Title] Add logger [Type] [Module] [Priority] [Jira#] [Redmine#] 7571 [Problem] [Cause] [Solution] [TestCase] Change-Id: Ib91b3ad723a0d22b3247d1762f996a75314e2ba4 --- diff --git a/org.tizen.common/.classpath b/org.tizen.common/.classpath index aab2b5a..3bc4976 100755 --- a/org.tizen.common/.classpath +++ b/org.tizen.common/.classpath @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.tizen.common/log4j.xml b/org.tizen.common/log4j.xml index b40a1bd..cb484bb 100644 --- a/org.tizen.common/log4j.xml +++ b/org.tizen.common/log4j.xml @@ -31,7 +31,7 @@ --> diff --git a/org.tizen.common/plugin.xml b/org.tizen.common/plugin.xml index 358a12a..6721fe5 100644 --- a/org.tizen.common/plugin.xml +++ b/org.tizen.common/plugin.xml @@ -38,12 +38,6 @@ id="org.tizen.common.preferences.rds" name="%RDS.name"> - - diff --git a/org.tizen.common/src/org/tizen/common/CommonPlugin.java b/org.tizen.common/src/org/tizen/common/CommonPlugin.java index 2ad69fb..c078315 100755 --- a/org.tizen.common/src/org/tizen/common/CommonPlugin.java +++ b/org.tizen.common/src/org/tizen/common/CommonPlugin.java @@ -45,6 +45,7 @@ import org.tizen.common.util.DialogUtil; import org.tizen.common.util.HostUtil; import org.tizen.common.util.OSChecker; import org.tizen.common.util.log.Logger; +import org.tizen.common.util.log.TizenLog4jConfigurator; import org.tizen.sdblib.CrashReportService; import org.tizen.sdblib.ICrashReportServiceListener; import org.tizen.sdblib.SmartDevelopmentBridge; @@ -79,6 +80,9 @@ public class CommonPlugin extends AbstractUIPlugin { @Override public void start(BundleContext context) throws Exception { super.start( context ); + + getPreferenceStore().addPropertyChangeListener( new TizenLog4jConfigurator() ); + plugin = this; initializeExecutor(); diff --git a/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.java b/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.java index ec48dd8..576a112 100644 --- a/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.java +++ b/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.java @@ -43,6 +43,22 @@ public class Messages { public static String RDS_OPTION_SAVE_FAIL; public static String RDS_MODE_PREFERENCE; + public static String LOGGER_GROUP; + public static String LABEL_LOG_LOCATION; + public static String LABEL_LOG_CP; + + public static String BUTTON_REPORT; + public static String BUTTON_USAGE; + public static String BUTTON_PERFORM; + + public static String DES_OFF; + public static String DES_ERROR; + public static String DES_WARN; + public static String DES_INFO; + public static String DES_DEBUG; + public static String DES_ALL; + + static { // initialize resource bundle NLS.initializeMessages( BUNDLE_NAME, Messages.class ); diff --git a/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.properties b/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.properties index 8197247..e59d6ea 100644 --- a/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.properties +++ b/org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.properties @@ -6,4 +6,10 @@ LABEL_UPDATE=Automatically find new updates at start-up and notify me PROPERTIES_PAGE_BODY=Expand the tree to edit preferences for a specific feature. RDS_NOTE=Currently, this option is not supported for multi-app project. RDS_OPTION_SAVE_FAIL=Failed to save options. -RDS_MODE_PREFERENCE=Enable rapid development mode \ No newline at end of file +RDS_MODE_PREFERENCE=Enable rapid development mode +LOGGER_GROUP=Logger +LABEL_LOG_LOCATION=&Location +LABEL_LOG_CP=&Pattern +BUTTON_REPORT=I want to contribute this information to improve Tizen IDE +BUTTON_USAGE=Send usage data +BUTTON_PERFORM=Send performance data \ No newline at end of file diff --git a/org.tizen.common/src/org/tizen/common/ui/page/preference/TizenBasePreferencePage.java b/org.tizen.common/src/org/tizen/common/ui/page/preference/TizenBasePreferencePage.java index 41696eb..4c5b209 100644 --- a/org.tizen.common/src/org/tizen/common/ui/page/preference/TizenBasePreferencePage.java +++ b/org.tizen.common/src/org/tizen/common/ui/page/preference/TizenBasePreferencePage.java @@ -28,13 +28,27 @@ package org.tizen.common.ui.page.preference; import org.eclipse.jface.preference.BooleanFieldEditor; import org.eclipse.jface.preference.DirectoryFieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +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.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Scale; +import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.tizen.common.CommonPlugin; import org.tizen.common.util.SWTUtil; +import org.tizen.common.util.StringUtil; +import org.tizen.common.util.log.FileAppender; +import org.tizen.common.util.log.Level; +import org.tizen.common.util.log.LoggerConstants; public class TizenBasePreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage @@ -45,9 +59,33 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement public static final String KEY_SDKLOCATION = "sdkpath"; //$NON-NLS-1$ public static final String KEY_SDKUPDATE = "sdkupdate"; //$NON-NLS-1$ + public static final String VALUE_SDKLOCATION_DEFAULT = null;; public static final boolean VALUE_SDKUPDATE_DEFAULT = false; + + public static final String OPTION_ID_LEVEL = "org.tizen.common.logger.level"; + public static final String OPTION_ID_LOCATION = "org.tizen.common.logger.location"; + public static final String OPTION_ID_CP = "org.tizen.common.logger.cp"; + public static final String OPTION_ID_REPORT = "org.tizen.common.logger.report"; + public static final String OPTION_ID_USAGE = "org.tizen.common.logger.usage"; + public static final String OPTION_ID_PERFORM = "org.tizen.common.logger.perform"; + + private static final String DEFAULT_LOG_LOCATION = "%X{" + LoggerConstants.KEY_WORKSPACE + "}/.metadata/log.%d"; + + private static final int DEFAULT_LEVEL = 1; + private static final Level[] LEVELS = {Level.OFF, Level.ERROR, Level.WARNING, Level.INFO, Level.DEBUG, Level.ALL}; + + private Text loggerCP; + private Text loggerLocText; + private Scale levelScale; + private Label levelDesLabel; + private Button reportButton; + private Button usageButton; + private Button performButton; + + private static final IPreferenceStore prefStore = (CommonPlugin.getDefault() == null) ? null : CommonPlugin.getDefault().getPreferenceStore(); + public TizenBasePreferencePage() { // super(GRID); @@ -58,9 +96,7 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement } @Override - public void init(IWorkbench workbench) - { - // TODO Auto-generated method stub + public void init(IWorkbench workbench) { } @Override @@ -82,6 +118,7 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement SWTUtil.createSpacer(composite, 1); createUpdateSettingPreferences(composite); SWTUtil.createSpacer(composite, 1); + createLoggerPreferences(composite); } private void createPathSettingPreferences(Composite parent) @@ -103,5 +140,256 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement Messages.LABEL_UPDATE, formatComposite); addField(startupCheckEditor); } + + + private void addLoggerListener() { + } + + private void setLoggerButtonEnablement() { + if(prefStore.getBoolean(OPTION_ID_REPORT)) { + reportButton.setSelection(true); + } + } + + private void createLoggerPreferences(Composite parent) { + Composite comp = SWTUtil.createGroup(parent, Messages.LOGGER_GROUP, 1); + SWTUtil.setGridLayout(comp, 2, false, -1, -1, -1, -1, GridData.FILL_HORIZONTAL); + createLoggerLocationButton(comp); + createLoggerConversionPatterhn(comp); + createLoggerLevelButtons(comp); + createLoggerReportButtons(comp); + + addLoggerListener(); + setLoggerButtonEnablement(); + } + + private void createLoggerConversionPatterhn(Composite parent) { + Label loggerLocationLabel = new Label(parent, SWT.None); + loggerLocationLabel.setText(Messages.LABEL_LOG_CP); + + loggerCP = new Text(parent, SWT.BORDER); + SWTUtil.setGridLayoutData(loggerCP, -1, -1, -1, -1, GridData.FILL_HORIZONTAL); + + loggerCP.setText(getLogConversionPattern()); + } + + private void createLoggerReportButtons(Composite parent) { + Composite comp = new Composite(parent, SWT.None); + SWTUtil.setGridLayout(comp, 2, false, -1, -1, -1, -1, GridData.FILL_HORIZONTAL); + SWTUtil.setGridLayoutData(comp, -1, -1, 2, -1, GridData.FILL_HORIZONTAL); + + reportButton = new Button(comp, SWT.CHECK); + SWTUtil.setGridLayoutData(reportButton, -1, -1, 2, -1, GridData.FILL_HORIZONTAL); + reportButton.setText(Messages.BUTTON_REPORT); + + Label emptyLabel = new Label(comp, SWT.None); + emptyLabel.setText(" "); + + usageButton = new Button(comp, SWT.CHECK); + SWTUtil.setGridLayoutData(usageButton, -1, -1, -1, -1, GridData.FILL_HORIZONTAL); + usageButton.setText(Messages.BUTTON_USAGE); + + Label emptyLabel2 = new Label(comp, SWT.None); + emptyLabel2.setText(" "); + + performButton = new Button(comp, SWT.CHECK); + SWTUtil.setGridLayoutData(performButton, -1, -1, -1, -1, GridData.FILL_HORIZONTAL); + performButton.setText(Messages.BUTTON_PERFORM); + + if(prefStore.getBoolean(OPTION_ID_REPORT)) { + reportButton.setSelection(true); + if(prefStore.getBoolean(OPTION_ID_USAGE)) { + usageButton.setSelection(true); + } + if(prefStore.getBoolean(OPTION_ID_PERFORM)) { + performButton.setSelection(true); + } + } + + checkLoggerButton(); + + reportButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + checkLoggerButton(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + } + + private void checkLoggerButton() { + if(!reportButton.getSelection()) { + usageButton.setSelection(false); + usageButton.setEnabled(false); + performButton.setSelection(false); + performButton.setEnabled(false); + } + else { + usageButton.setEnabled(true); + performButton.setEnabled(true); + } + } + + private void createLoggerLocationButton(Composite parent) { + Label loggerLocationLabel = new Label(parent, SWT.None); + loggerLocationLabel.setText(Messages.LABEL_LOG_LOCATION); + + loggerLocText = new Text(parent, SWT.BORDER); + SWTUtil.setGridLayoutData(loggerLocText, -1, -1, -1, -1, GridData.FILL_HORIZONTAL); + + loggerLocText.setText(getLogLocation()); + } + + public static String getLogConversionPattern() { + + String loggerCP = prefStore.getString(OPTION_ID_CP); + if(StringUtil.isEmpty(loggerCP)) { + loggerCP = LoggerConstants.DEFAULT_CONVERSION_PATTERN; + } + + return loggerCP; + } + + public static String getLogLocation() { + + String loggerPath = prefStore.getString(OPTION_ID_LOCATION); + if(StringUtil.isEmpty(loggerPath)) { + loggerPath = DEFAULT_LOG_LOCATION; + } + + return loggerPath; + } + + private void createLoggerLevelButtons(Composite parent) { + String selectedLevel = prefStore.getString(OPTION_ID_LEVEL); + if(StringUtil.isEmpty(selectedLevel)) { + selectedLevel = LEVELS[DEFAULT_LEVEL].toString(); + } + + levelScale = new Scale(parent, SWT.HORIZONTAL); + SWTUtil.setGridLayoutData(levelScale, -1, -1, 2, -1, GridData.FILL_HORIZONTAL); + levelScale.setMinimum(0); + levelScale.setMaximum(LEVELS.length - 1); + levelScale.setIncrement(1); + levelScale.setPageIncrement(1); +// levelScale.setDragDetect(false); + + boolean levelDefined = false; + for(int i=0; itrue. Else, false. * @return appended path */ public static String appendPath(String originalPath, String appendPath, boolean isWindows) { diff --git a/org.tizen.common/src/org/tizen/common/util/SWTUtil.java b/org.tizen.common/src/org/tizen/common/util/SWTUtil.java index f8369bf..6b75138 100755 --- a/org.tizen.common/src/org/tizen/common/util/SWTUtil.java +++ b/org.tizen.common/src/org/tizen/common/util/SWTUtil.java @@ -480,6 +480,25 @@ public class SWTUtil { } } while (!treeStack.isEmpty()); } + + /** + * set grid layout of the Control + * If values of heightHint, widthHint, horizontalSpan, verticalSpan is -1, this method does not change value of them + * + * @param c target control to which grid layout data is set + * @param numColumns the number of columns in the grid + * @param equalWidth whether or not the columns will have equal width + * @param heightHint height of the control + * @param widthHint width of the control + * @param horizontalSpan the number of column cells that control will take up + * @param verticalSpan the number of row cells that control will take up + * @param style style of the control + * @author Ho Namkoong {@literal } (S-Core) + */ + public static void setGridLayout(Composite c, int numColumns, boolean equalWidth, int heightHint, int widthHint, int horizontalSpan, int verticalSpan, int style) { + c.setLayout(new GridLayout(numColumns, equalWidth)); + SWTUtil.setGridLayoutData(c, heightHint, widthHint, horizontalSpan, verticalSpan, style); + } /** * set grid layout data of Control. diff --git a/org.tizen.common/src/org/tizen/common/util/ThreadLocalMap.java b/org.tizen.common/src/org/tizen/common/util/ThreadLocalMap.java new file mode 100644 index 0000000..c0b1aae --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/ThreadLocalMap.java @@ -0,0 +1,112 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * ThreadLocalMap which implements {@link Map}} has one map per one thread + * @see ThreadLocal + * @see Map + * @author ho.namkoong + */ +public class ThreadLocalMap +implements Map { + + /** + * contains one map per one thread + */ + private ThreadLocal> threadLocal = new ThreadLocal>() { + + protected Map initialValue() { + return new HashMap(); + }; + }; + + @Override + public int size() { + return threadLocal.get().size(); + } + + @Override + public boolean isEmpty() { + return threadLocal.get().isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return threadLocal.get().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return threadLocal.get().containsValue(value); + } + + @Override + public V get(Object key) { + return threadLocal.get().get(key); + } + + @Override + public V put(K key, V value) { + return threadLocal.get().put(key, value); + } + + @Override + public V remove(Object key) { + return threadLocal.get().remove(key); + } + + @Override + public void putAll(Map m) { + threadLocal.get().putAll(m); + } + + @Override + public void clear() { + threadLocal.get().clear(); + } + + @Override + public Set keySet() { + return threadLocal.get().keySet(); + } + + @Override + public Collection values() { + return threadLocal.get().values(); + } + + @Override + public Set> entrySet() { + return threadLocal.get().entrySet(); + } +} diff --git a/org.tizen.common/src/org/tizen/common/util/log/TizenLog4jAppender.java b/org.tizen.common/src/org/tizen/common/util/log/EclipseAppender.java similarity index 82% rename from org.tizen.common/src/org/tizen/common/util/log/TizenLog4jAppender.java rename to org.tizen.common/src/org/tizen/common/util/log/EclipseAppender.java index c492d9a..be90f21 100644 --- a/org.tizen.common/src/org/tizen/common/util/log/TizenLog4jAppender.java +++ b/org.tizen.common/src/org/tizen/common/util/log/EclipseAppender.java @@ -26,11 +26,22 @@ package org.tizen.common.util.log; import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.EnhancedPatternLayout; +import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.spi.LoggingEvent; import org.apache.log4j.spi.ThrowableInformation; -public class TizenLog4jAppender extends AppenderSkeleton{ +public class EclipseAppender extends AppenderSkeleton{ + + public EclipseAppender() { + this(new EnhancedPatternLayout(LoggerConstants.DEFAULT_CONVERSION_PATTERN)); + } + + public EclipseAppender(Layout layout) { + super(); + setLayout(layout); + } @Override public void close() { @@ -52,8 +63,8 @@ public class TizenLog4jAppender extends AppenderSkeleton{ if(tI != null) { t = tI.getThrowable(); } - Object msg = arg0.getMessage(); - String message = msg.toString(); + + String message = arg0.getMessage().toString(); switch (level) { case Level.ERROR_INT: diff --git a/org.tizen.common/src/org/tizen/common/util/log/FileAppender.java b/org.tizen.common/src/org/tizen/common/util/log/FileAppender.java new file mode 100644 index 0000000..5bcc11a --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/FileAppender.java @@ -0,0 +1,188 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util.log; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Timer; +import java.util.TimerTask; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.EnhancedPatternLayout; +import org.apache.log4j.Layout; +import org.apache.log4j.Logger; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.spi.LoggingEvent; +import org.eclipse.osgi.util.NLS; +import org.tizen.common.util.IOUtil; +import org.tizen.common.util.StringUtil; + +public class FileAppender extends AppenderSkeleton{ + + private int bufferSize; + //This event is dummy for getting formatted workspace path. + private static final LoggingEvent dummy = new LoggingEvent( null, Logger.getLogger( "FileAppender"), Level.OFF, StringUtil.EMPTY_STRING, null ); + + protected final OutputStream NOOP_OUTPUT_STREAM = new OutputStream() { + + @Override + public void write(int b) throws IOException { + } + }; + + protected final FileAppenderScheduler NOOP_SCHEDULER = new FileAppenderScheduler() { + + @Override + public void run() {} + + @Override + public boolean cancel() { + return true; + } + }; + + private OutputStream FILE_OUTPUT_STREAM; + private FileAppenderScheduler SCHEDULER; + private static final Timer TIMER = new Timer("File appender timer", true); + protected String logPath; + + public FileAppender(String logPath) { + this(logPath, new EnhancedPatternLayout(LoggerConstants.DEFAULT_CONVERSION_PATTERN), LoggerConstants.DEFAULT_BUFFER_SIZE); + } + + public FileAppender(String logPath, Layout layout) { + this(logPath, layout, LoggerConstants.DEFAULT_BUFFER_SIZE); + } + + public FileAppender(String logPath, Layout layout, int bufferSize) { + super(); + this.logPath = new EnhancedPatternLayout(logPath).format(dummy); + this.bufferSize = bufferSize; + setLayout(layout); + initializeAppender(); + } + + @Override + public void close() { + } + + @Override + public boolean requiresLayout() { + return false; + } + + synchronized public void setFilePath( final String path ) { + IOUtil.tryFlush(FILE_OUTPUT_STREAM); + IOUtil.tryClose(FILE_OUTPUT_STREAM); + EnhancedPatternLayout layout = new EnhancedPatternLayout(path); + this.logPath = layout.format(dummy); + initializeAppender(); + } + + synchronized public void setBufferSize(final int bufferSize) { + IOUtil.tryFlush(FILE_OUTPUT_STREAM); + IOUtil.tryClose(FILE_OUTPUT_STREAM); + this.bufferSize = bufferSize; + initializeAppender(); + } + + @Override + synchronized protected void append(LoggingEvent arg0) { + + try { + FILE_OUTPUT_STREAM.write(layout.format(arg0).getBytes()); + + if(getLayout().ignoresThrowable()) { + String[] tss = arg0.getThrowableStrRep(); + if(tss != null) { + for(String ts: tss) { + FILE_OUTPUT_STREAM.write((ts + "\n").getBytes()); + } + } + } + } catch (IOException e) { + LogLog.error(Messages.FileAppender_EXCEPTION_WRITING_LOG, e); //$NON-NLS-1$ + } + + SCHEDULER.cancel(); + SCHEDULER = new FileAppenderScheduler(); + TIMER.scheduleAtFixedRate(SCHEDULER, LoggerConstants.DEFAULT_TIMER_PERIOD, LoggerConstants.DEFAULT_TIMER_PERIOD); + } + + synchronized private void initializeAppender() { + + File logFile = new File(logPath); + + if(!logFile.exists()) { + logFile.getAbsoluteFile().getParentFile().mkdirs(); + try { + logFile.createNewFile(); + } catch (IOException e) { + FILE_OUTPUT_STREAM = NOOP_OUTPUT_STREAM; + SCHEDULER = NOOP_SCHEDULER; + LogLog.error(NLS.bind(Messages.FileAppender_EXCEPTION_CREATING_LOGFILE, logPath), e); //$NON-NLS-1$ + return; + } + } + else if(logFile.isDirectory()) { + FILE_OUTPUT_STREAM = NOOP_OUTPUT_STREAM; + SCHEDULER = NOOP_SCHEDULER; + LogLog.error(NLS.bind(Messages.FileAppender_EXCEPTION_DIRECTORY_EXISTING, logPath)); + return; + } + + IOUtil.tryFlush(FILE_OUTPUT_STREAM); + IOUtil.tryClose(FILE_OUTPUT_STREAM); + try { + FILE_OUTPUT_STREAM = new BufferedOutputStream( new FileOutputStream(logPath, true), this.bufferSize ); + } catch (IOException e) { + FILE_OUTPUT_STREAM = NOOP_OUTPUT_STREAM; + SCHEDULER = NOOP_SCHEDULER; + LogLog.error(Messages.FileAppender_EXCEPTION_CREATING_BUFFER, e); //$NON-NLS-1$ + return; + } + + SCHEDULER = new FileAppenderScheduler(); + TIMER.scheduleAtFixedRate(SCHEDULER, LoggerConstants.DEFAULT_TIMER_PERIOD, LoggerConstants.DEFAULT_TIMER_PERIOD); + } + + public class FileAppenderScheduler extends TimerTask { + @Override + public void run() { + synchronized ( FileAppender.this ) { + try { + FILE_OUTPUT_STREAM.flush(); + } catch (IOException e) { + LogLog.error(Messages.FileAppender_EXCEPTION_FLUSHING_BUFFER, e); + } + } + } + } +} diff --git a/org.tizen.common/src/org/tizen/common/util/log/GoogleAnalyticAppender.java b/org.tizen.common/src/org/tizen/common/util/log/GoogleAnalyticAppender.java new file mode 100644 index 0000000..bac9a22 --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/GoogleAnalyticAppender.java @@ -0,0 +1,288 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util.log; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.EnhancedPatternLayout; +import org.apache.log4j.Layout; +import org.apache.log4j.Level; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.spi.LoggingEvent; +import org.tizen.common.util.ObjectUtil; +import org.tizen.common.util.log.UserLogger.Event; +import org.tizen.common.util.log.UserLogger.Page; +import org.tizen.common.util.log.UserLogger.PerformanceInfo; + +public +class +GoogleAnalyticAppender +extends AppenderSkeleton +{ + private boolean isUsage = false; + private boolean isPerform = false; + static final String URL_GOOGLE_ANALYTIC = "http://www.google-analytics.com/collect"; + private static final int MAX_STACK_TRACE = 2; + + private static final String KEY_ANALYTIC_VER = "v"; + private static final String KEY_TRACKING_ID = "tid"; + private static final String KEY_CLIENT_ID = "cid"; + private static final String KEY_HIT_TYPE = "t"; + private static final String KEY_APP_NAME = "an"; + private static final String KEY_APP_VER = "av"; + private static final String KEY_CONTENT_DES = "cd"; + private static final String KEY_EVENT_CATEGORY = "ec"; + private static final String KEY_EVENT_ACTION = "ea"; + private static final String KEY_PERFORM_CATEGORY = "utc"; + private static final String KEY_PERFORM_VARIABLE = "utv"; + private static final String KEY_PERFORM_TIME = "utt"; + private static final String KEY_EXCEPTION = "exd"; + private static final String KEY_FATAL = "exf"; + + private static final String VALUE_ANALYTIC_VER = "1"; + private static final String VALUE_TRACKING_ID = "UA-33537119-1"; + private static final String VALUE_CLIENT_ID = ObjectUtil.generateGUID( GoogleAnalyticAppender.class ); + private static final String VALUE_APP_NAME = "tizen-ide"; + private static final String VALUE_APP_VER = "2.1"; + private static final String VALUE_HIT_TYPE_TIMING = "timing"; + private static final String VALUE_HIT_TYPE_EVENT = "event"; +// private static final String VALUE_HIT_TYPE_PAGE = "page"; +// private static final String VALUE_HIT_TYPE_EXCEPTION = "exception"; + private static final String VALUE_HIT_TYPE_APP = "appview"; + int rc; + + public GoogleAnalyticAppender(boolean isUsage, boolean isPerform) { + this(isUsage, isPerform, new EnhancedPatternLayout(LoggerConstants.DEFAULT_CONVERSION_PATTERN)); + } + + public GoogleAnalyticAppender(boolean isUsage, boolean isPerform, Layout layout) { + super(); + this.isUsage = isUsage; + this.isPerform = isPerform; + setLayout(layout); + } + + public void setUsage(boolean isUsage) { + this.isUsage = isUsage; + } + + public void setPerform(boolean isPerform) { + this.isPerform = isPerform; + } + + @Override + public + void + close() + { + } + + @Override + public boolean requiresLayout() + { + return false; + } + + protected String + assembly( + final String key, + final String value + ) + throws UnsupportedEncodingException + { + return URLEncoder.encode( key, "utf-8" ) + "=" + URLEncoder.encode( value, "utf-8" ); + } + + protected + String + join( String... props ) + { + final StringBuilder buffer = new StringBuilder( 1000 ); + for ( int i = 0, n = props.length ; i result = new ArrayList(); + try { + if(!assembleString(result, event)) { + return; + } + } catch (UnsupportedEncodingException e) { + LogLog.error("Exception occurred while creating google analytic message", e); + return; + } + + final String resultData = join(result.toArray(new String[result.size()])); + + try + { + final URL u = new URL( URL_GOOGLE_ANALYTIC ); + final HttpURLConnection con = (HttpURLConnection) u.openConnection(); + try + { + con.setDoOutput( true ); + final OutputStream out = con.getOutputStream(); + final OutputStreamWriter writer = new OutputStreamWriter( out ); + writer.write( resultData ); + writer.flush(); + + rc = con.getResponseCode(); + if ( 200 <= rc && rc < 300 ) + { + System.out.println("OK"); + } + } + finally + { + con.disconnect(); + } + } catch (MalformedURLException e) + { + LogLog.debug( String.format("Malformed URL: %s", URL_GOOGLE_ANALYTIC), e ); + } catch (IOException e) + { + e.printStackTrace(); + LogLog.debug( "Exception occurred while transmitting google analytic data.", e ); + } + } + + private boolean assembleString(ArrayList result, LoggingEvent event) throws UnsupportedEncodingException { + + Level level = event.getLevel(); + if(level == org.tizen.common.util.log.Level.PERFORM_END) { + if(!isPerform) { + return false; + } + PerformanceInfo perform = (PerformanceInfo) event.getMessage(); + addPerformPreVariables(result, perform); + result.add(assembly(KEY_PERFORM_TIME, perform.getPerformanceString())); + } + else if(level == org.tizen.common.util.log.Level.PERFORM_START) { + if(!isPerform) { + return false; + } + PerformanceInfo perform = (PerformanceInfo) event.getMessage(); + addPerformPreVariables(result, perform); + } + else if(level == org.tizen.common.util.log.Level.PAGE) { + if(!isUsage) { + return false; + } + addPageVariable(result, (Page)event.getMessage()); + } + else if(level == org.tizen.common.util.log.Level.EVENT) { + if(!isUsage) { + return false; + } + addEventVariable(result, (Event)event.getMessage()); + } + else { + result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_APP)); + } + + addBasicInfo(result, event); + return true; + } + + private void addPageVariable(ArrayList result, Page page) throws UnsupportedEncodingException { + result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_EVENT)); + result.add(assembly(KEY_EVENT_CATEGORY, page.getCategory())); + } + + private void addEventVariable(ArrayList result, Event event) throws UnsupportedEncodingException { + result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_EVENT)); + result.add(assembly(KEY_EVENT_CATEGORY, event.getCategory())); + result.add(assembly(KEY_EVENT_ACTION, event.getAction())); + } + + private void addPerformPreVariables(ArrayList result, PerformanceInfo performanceInfo) throws UnsupportedEncodingException { + result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_TIMING)); + result.add(assembly(KEY_PERFORM_CATEGORY, performanceInfo.getCategory())); + result.add(assembly(KEY_PERFORM_VARIABLE, performanceInfo.getVariableName())); + } + + private void addBasicInfo(ArrayList result, LoggingEvent event) throws UnsupportedEncodingException { + + //HTTP error 413 occurred if request entity is too large. Just getting the first tss. + String[] tss = event.getThrowableStrRep(); + Level level = event.getLevel(); + StringBuffer msg = new StringBuffer(); + msg.append(getLayout().format(event)); + if(tss != null) { + + if(level == org.tizen.common.util.log.Level.FATAL) { + result.add(assembly(KEY_FATAL, "FATAL")); + } + StringBuffer tBuffer = new StringBuffer(); + + int i=0; + for(String ts: tss) { + if(MAX_STACK_TRACE > i + 1) { + tBuffer.append(ts + "\n"); + i++; + } + else { + break; + } + } + result.add(assembly(KEY_EXCEPTION, tBuffer.toString())); + + if(getLayout().ignoresThrowable()) { + msg.append(tBuffer); + } + } + result.add(assembly(KEY_ANALYTIC_VER, VALUE_ANALYTIC_VER)); + result.add(assembly(KEY_TRACKING_ID, VALUE_TRACKING_ID)); + result.add(assembly(KEY_CLIENT_ID, VALUE_CLIENT_ID)); + result.add(assembly(KEY_APP_NAME, VALUE_APP_NAME)); + result.add(assembly(KEY_APP_VER, VALUE_APP_VER)); + result.add(assembly(KEY_CONTENT_DES, msg.toString())); + } +} \ No newline at end of file diff --git a/org.tizen.common/src/org/tizen/common/util/log/Level.java b/org.tizen.common/src/org/tizen/common/util/log/Level.java new file mode 100644 index 0000000..c84597d --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/Level.java @@ -0,0 +1,106 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + + +package org.tizen.common.util.log; + +public class Level extends org.apache.log4j.Level{ + + private static final long serialVersionUID = 5540784843364335844L; + + /** + * Logging level page + */ + public static final Level PAGE = new Level(25000, "PAGE", 5); + + /** + * Logging level event + */ + public static final Level EVENT = new Level(23000, "EVENT", 5); + + /** + * Logging level performance start + */ + public static final Level PERFORM_START = new Level(27000, "PERFORM_START", 5); + + /** + * Logging level performance end + */ + public static final Level PERFORM_END = new Level(27000, "PERFFORM_END", 5); + + /** + * Logging level off + */ + public static final Level OFF = new Level(org.apache.log4j.Level.OFF, Messages.LOGGER_OFF_DES); + + /** + * Logging level error + */ + public static final Level ERROR = new Level(org.apache.log4j.Level.ERROR, Messages.LOGGER_ERROR_DES); + + /** + * Logging level warning + */ + public static final Level WARNING = new Level(org.apache.log4j.Level.WARN, Messages.LOGGER_WARNING_DES); + + /** + * Logging level info + */ + public static final Level INFO = new Level(org.apache.log4j.Level.INFO, Messages.LOGGER_INFO_DES); + + /** + * Logging level debug + */ + public static final Level DEBUG = new Level(org.apache.log4j.Level.DEBUG, Messages.LOGGER_DEBUG_DES); + + /** + * Logging level all + */ + public static final Level ALL = new Level(org.apache.log4j.Level.ALL, Messages.LOGGER_ALL_DES); + + private String description; + + protected Level(int level, String levelStr, int syslogEquivalent) { + super(level, levelStr, syslogEquivalent); + this.description = ""; + } + + protected Level(org.apache.log4j.Level level, String desc) { + this(level.toInt(), level.toString(), level.getSyslogEquivalent()); + this.description = desc; + } + + public String getDescription() { + return description; + } + + + @Override + public int hashCode() { + // TODO Auto-generated method stub + return toString().hashCode(); + } +} diff --git a/org.tizen.common/src/org/tizen/common/util/log/Logger.java b/org.tizen.common/src/org/tizen/common/util/log/Logger.java index 59d1721..050b7e3 100644 --- a/org.tizen.common/src/org/tizen/common/util/log/Logger.java +++ b/org.tizen.common/src/org/tizen/common/util/log/Logger.java @@ -37,10 +37,17 @@ import org.tizen.common.ui.view.console.ConsoleManager; /** * Logger. * @author Changhyun Lee {@literal } (S-Core) + * @deprecated Use {@link org.slf4j.Logger}} instead. */ public class Logger { private static String loggerName = Logger.class.getName(); + + /** + * + * @param status + * @deprecated Use {@link org.apache.log4j.Logger#log(org.apache.log4j.Priority, Object)} instead + */ public static void log(IStatus status) { CommonPlugin plugin = CommonPlugin.getDefault(); if (plugin != null) { @@ -67,6 +74,11 @@ public class Logger { return "noname"; } + /** + * + * @param e + * @deprecated Use {@link org.apache.log4j.Logger#log(org.apache.log4j.Priority, Object, Throwable)} instead + */ public static void log(Throwable e) { if (e instanceof CoreException) { log(new Status(IStatus.ERROR, getCallerName(), ((CoreException) e).getStatus().getSeverity(), e.getMessage(), e.getCause())); @@ -74,24 +86,43 @@ public class Logger { log(new Status(IStatus.ERROR, getCallerName(), e.toString(), e)); } } - - public static void debug( String message, Object... arguments ) - { - - } + /** + * + * @param message + * @param arguments + * @deprecated Use {@link org.slf4j.Logger#info(String, Object[])} instead + */ public static void info(String message, Object... arguments) { log(new Status(Status.INFO, getCallerName(), getPossiblyFormattedString(message, arguments))); } + /** + * + * @param message + * @param t + * @deprecated Use {@link org.slf4j.Logger#error(String, Throwable)} instead + */ public static void error(Object message, Throwable t) { log(new Status(Status.ERROR, getCallerName(), message.toString(), t)); } + /** + * + * @param message + * @param arguments + * @deprecated Use {@link org.slf4j.Logger#error(String, Object[])} instead + */ public static void error(String message, Object... arguments) { log(new Status(Status.ERROR, getCallerName(), getPossiblyFormattedString(message, arguments))); } + /** + * + * @param message + * @param arguments + * @deprecated Use {@link org.slf4j.Logger#warn(String, Object[])} instead + */ public static void warning(String message, Object... arguments) { log(new Status(Status.WARNING, getCallerName(), getPossiblyFormattedString(message, arguments))); } diff --git a/org.tizen.common/src/org/tizen/common/util/log/LoggerConstants.java b/org.tizen.common/src/org/tizen/common/util/log/LoggerConstants.java new file mode 100644 index 0000000..a56c862 --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/LoggerConstants.java @@ -0,0 +1,38 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + + +package org.tizen.common.util.log; + +public class LoggerConstants { + + public static final String DEFAULT_CONVERSION_PATTERN = "[%p] %F(%L) - %m%n"; + public static final int DEFAULT_BUFFER_SIZE = 5000; + public static final long DEFAULT_TIMER_PERIOD = 3000; + public static final String KEY_WORKSPACE = "workspace"; + public static final String KEY_SDK_HOME = "tizensdk"; + +} diff --git a/org.tizen.common/src/org/tizen/common/util/log/Messages.java b/org.tizen.common/src/org/tizen/common/util/log/Messages.java new file mode 100644 index 0000000..30bd24b --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/Messages.java @@ -0,0 +1,56 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util.log; + +import org.eclipse.osgi.util.NLS; +import org.tizen.common.CommonPlugin; + +public class Messages { + + private static final String BUNDLE_NAME = CommonPlugin.PLUGIN_ID + ".util.log.messages";//$NON-NLS-1$ + + private Messages() { + // Do not instantiate + } + + public static String UserLogger_EVENT_STRING; + public static String FileAppender_EXCEPTION_FLUSHING_BUFFER; + public static String FileAppender_EXCEPTION_CREATING_BUFFER; + public static String FileAppender_EXCEPTION_CREATING_LOGFILE; + public static String FileAppender_EXCEPTION_WRITING_LOG; + public static String FileAppender_EXCEPTION_DIRECTORY_EXISTING; + public static String LOGGER_OFF_DES; + public static String LOGGER_ERROR_DES; + public static String LOGGER_WARNING_DES; + public static String LOGGER_INFO_DES; + public static String LOGGER_DEBUG_DES; + public static String LOGGER_ALL_DES; + + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } +} diff --git a/org.tizen.common/src/org/tizen/common/util/log/TizenLog4Configurator.java b/org.tizen.common/src/org/tizen/common/util/log/TizenLog4Configurator.java deleted file mode 100644 index 3ddac07..0000000 --- a/org.tizen.common/src/org/tizen/common/util/log/TizenLog4Configurator.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Common - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: - * Ho Namkoong - * - * 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. - * - * Contributors: - * - S-Core Co., Ltd - * - */ - -package org.tizen.common.util.log; - -import java.io.InputStream; -import java.net.URL; - -import org.apache.log4j.Appender; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.apache.log4j.spi.Configurator; -import org.apache.log4j.spi.LoggerRepository; -import org.tizen.common.util.log.preference.TizenLoggerPreferencePage; - -public class TizenLog4Configurator implements Configurator { - - private static Logger ROOT_LOGGER; - - @Override - public void doConfigure(InputStream arg0, LoggerRepository arg1) { - // TODO Auto-generated method stub - } - - @Override - public void doConfigure(URL arg0, LoggerRepository arg1) { - arg1.resetConfiguration(); - Logger rootLogger = arg1.getRootLogger(); - - rootLogger.removeAllAppenders(); - Appender tizenAppender = new TizenLog4jAppender(); - rootLogger.addAppender(tizenAppender); - ROOT_LOGGER = rootLogger; - - setLoggerLevel(TizenLoggerPreferencePage.getLoggerLevel()); - } - - public static void setLoggerLevel(String level) { - if(ROOT_LOGGER != null) { - if(TizenLoggerPreferencePage.LEVEL_ERROR.equals(level)) { - ROOT_LOGGER.setLevel(Level.ERROR); - } - else if(TizenLoggerPreferencePage.LEVEL_WARN.equals(level)) { - ROOT_LOGGER.setLevel(Level.WARN); - } - else if(TizenLoggerPreferencePage.LEVEL_INFO.equals(level)) { - ROOT_LOGGER.setLevel(Level.INFO); - } - else if(TizenLoggerPreferencePage.LEVEL_DEBUG.equals(level)) { - ROOT_LOGGER.setLevel(Level.DEBUG); - } - } - } - -} diff --git a/org.tizen.common/src/org/tizen/common/util/log/TizenLog4jConfigurator.java b/org.tizen.common/src/org/tizen/common/util/log/TizenLog4jConfigurator.java new file mode 100644 index 0000000..deeaa56 --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/TizenLog4jConfigurator.java @@ -0,0 +1,138 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util.log; + +import java.io.InputStream; +import java.net.URL; + +import org.apache.log4j.AsyncAppender; +import org.apache.log4j.EnhancedPatternLayout; +import org.apache.log4j.Logger; +import org.apache.log4j.MDC; +import org.apache.log4j.spi.LoggerRepository; +import org.apache.log4j.xml.DOMConfigurator; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.tizen.common.core.application.InstallPathConfig; +import org.tizen.common.ui.page.preference.TizenBasePreferencePage; + +public class TizenLog4jConfigurator extends DOMConfigurator implements IPropertyChangeListener { + + private static Logger rootLogger; + private static Logger userLogger; + private static FileAppender fileAppender; + private static AsyncAppender asyncAppender; + private static GoogleAnalyticAppender googleAppender; + private static EclipseAppender eclipseAppender; + + private static final EnhancedPatternLayout layout = new EnhancedPatternLayout(); + + @Override + public void doConfigure(InputStream arg0, LoggerRepository arg1) { + // TODO Auto-generated method stub + } + + @Override + public void doConfigure(URL arg0, LoggerRepository arg1) { + arg1.resetConfiguration(); + layout.setConversionPattern(TizenBasePreferencePage.getLogConversionPattern()); + configRootLogger(arg1); + configUserLogger(); + } + + private void configUserLogger() { + userLogger = Logger.getLogger(UserLogger.NAME_USER_LOGGER); + asyncAppender = new AsyncAppender(); + googleAppender = new GoogleAnalyticAppender(TizenBasePreferencePage.isUsage(), TizenBasePreferencePage.isPerform(), layout); + asyncAppender.addAppender(googleAppender); + userLogger.addAppender(asyncAppender); + } + + private void configRootLogger(LoggerRepository arg1) { + Logger _rootLogger = arg1.getRootLogger(); + rootLogger = _rootLogger; + rootLogger.removeAllAppenders(); + rootLogger.setLevel(TizenBasePreferencePage.getLoggerLevel()); + + MDC.put(LoggerConstants.KEY_WORKSPACE, ResourcesPlugin.getWorkspace().getRoot().getLocation().toString()); + MDC.put(LoggerConstants.KEY_SDK_HOME, InstallPathConfig.getSDKPath()); + fileAppender = new FileAppender(TizenBasePreferencePage.getLogLocation(), layout); + rootLogger.addAppender(fileAppender); + MDC.remove(LoggerConstants.KEY_WORKSPACE); + MDC.remove(LoggerConstants.KEY_SDK_HOME); + + eclipseAppender = new EclipseAppender(layout); + rootLogger.addAppender(eclipseAppender); + } + + private void setLogFilePath(String name) { + MDC.put(LoggerConstants.KEY_WORKSPACE, ResourcesPlugin.getWorkspace().getRoot().getLocation().toString()); + MDC.put(LoggerConstants.KEY_SDK_HOME, InstallPathConfig.getSDKPath()); + fileAppender.setFilePath(name); + MDC.remove(LoggerConstants.KEY_WORKSPACE); + MDC.remove(LoggerConstants.KEY_SDK_HOME); + } + + @Override + public void propertyChange(PropertyChangeEvent event) { + String property = event.getProperty(); + + if(property.equals(TizenBasePreferencePage.OPTION_ID_LOCATION)) { + String newPath = (String) event.getNewValue(); + + setLogFilePath(newPath); + } + else if(property.equals(TizenBasePreferencePage.OPTION_ID_LEVEL)) { + String loggerLevel = (String) event.getNewValue(); + Level level = TizenBasePreferencePage.getLoggerLevel(loggerLevel); + rootLogger.setLevel(level); + userLogger.setLevel(level); + } + else if(property.equals(TizenBasePreferencePage.OPTION_ID_REPORT)) { + boolean isReport = (Boolean) event.getNewValue(); + if(isReport) { + asyncAppender.addAppender(googleAppender); + } + else { + asyncAppender.removeAppender(googleAppender); + } + } + else if(property.equals(TizenBasePreferencePage.OPTION_ID_USAGE)) { + boolean isUsage = (Boolean) event.getNewValue(); + googleAppender.setUsage(isUsage); + } + else if(property.equals(TizenBasePreferencePage.OPTION_ID_PERFORM)) { + boolean isPerform = (Boolean) event.getNewValue(); + googleAppender.setUsage(isPerform); + } + else if(property.equals(TizenBasePreferencePage.OPTION_ID_CP)) { + String cp = (String) event.getNewValue(); + layout.setConversionPattern(cp); + } + } + +} diff --git a/org.tizen.common/src/org/tizen/common/util/log/UserLogger.java b/org.tizen.common/src/org/tizen/common/util/log/UserLogger.java new file mode 100644 index 0000000..b594503 --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/UserLogger.java @@ -0,0 +1,219 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util.log; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.apache.log4j.Logger; +import org.tizen.common.util.StringUtil; +import org.tizen.common.util.ThreadLocalMap; + +public class UserLogger { + + protected static ThreadLocalMap id2perform = new ThreadLocalMap(); + + private static final String FQCN = UserLogger.class.getName(); + public static final String NAME_USER_LOGGER = "UserLogger"; + private static final SimpleDateFormat logDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + + private static Logger logger = Logger.getLogger(NAME_USER_LOGGER); + + public static void page(String category) { + page(category, null); + } + + public static void page(String category, Throwable t) { + if (Level.PAGE.isGreaterOrEqual(logger.getEffectiveLevel())) { + Page message = new Page(category); + System.out.println("LOGGING IN"); + logger.log(FQCN, Level.PAGE, message, t); + } + } + + public static void event(String category) { + event(category, StringUtil.EMPTY_STRING, null); + } + + public static void event(String category, String action) { + event(category, action, null); + } + + public static void event(String category, String action, Throwable t) { + if (Level.EVENT.isGreaterOrEqual(logger.getEffectiveLevel())) { + Event message = new Event(category, action); + logger.log(FQCN, Level.EVENT, message, t); + } + } + + public static void start(String category) { + start(category, StringUtil.EMPTY_STRING); + } + + public static void start(String category, String variableName) { + if(Level.PERFORM_START.isGreaterOrEqual(logger.getEffectiveLevel())) { + + long start = System.currentTimeMillis(); + id2perform.put( category + variableName, start ); + PerformanceInfo message = new PerformanceInfo(category, start, 0, variableName); + logger.log(FQCN, Level.PERFORM_START, message, null); + } + } + + public static void end(String category) { + end(category, StringUtil.EMPTY_STRING); + } + + public static void end(String category, String variableName) { + if (Level.PERFORM_END.isGreaterOrEqual(logger.getEffectiveLevel())) { + long end = System.currentTimeMillis(); + Long start = id2perform.remove(category + variableName); + if (null == start) { + return; + } + + PerformanceInfo message = new PerformanceInfo(category, start, end, variableName); + logger.log(FQCN, Level.PERFORM_END, message, null); + } + } + + public static class PerformanceInfo { + + final private String category; + final private long start; + final private long end; + final private String variableName; + final private String message; + + public PerformanceInfo(String category, long start, long end) { + this(category, start, end, null); + } + + public PerformanceInfo(String category, long start, long end, String variableName) { + this.category = category; + this.start = start; + this.end = end; + this.variableName = variableName; + if(end == 0) { + if(StringUtil.isEmpty(variableName)) { + this.message = String.format("[Category: %s] at %s", category, logDateFormat.format(new Date(start))); + } + else { + this.message = String.format("[Category: %s\tVariable: %s] at %s", category, variableName, logDateFormat.format(new Date(start))); + } + } + else { + if(StringUtil.isEmpty(variableName)) { + this.message = String.format("[Category: %s] at %s \t [%s(ms)]", category, logDateFormat.format(new Date(end)), getPerformanceString()); + } + else{ + this.message = String.format("[Category: %s\tVariable: %s] at %s \t [%s(ms)]", category, variableName, logDateFormat.format(new Date(end)), getPerformanceString()); + } + } + } + + @Override + public String toString() { + return this.message; + } + + public String getCategory() { + return category; + } + + public String getVariableName() { + return variableName; + } + + public String getPerformanceString() { + return String.format("%d", (this.end - this.start)); + } + } + + public static class Event { + + final private String category; + final private String action; + final private String message; + + public Event(String category) { + this(category, null); + } + + public Event(String category, String action) { + this.category = category; + this.action = action; + + if(StringUtil.isEmpty(action)) { + this.message = String.format( + "[Category: %s]", category + ); + } + else { + this.message = String.format( + "[Category: %s\tAction: %s]", category, + action); + } + + } + + public String getCategory() { + return category; + } + + public String getAction() { + return action; + } + + @Override + public String toString() { + return message; + } + } + + public static class Page { + + final private String category; + final private String message; + + public Page(String category) { + this.category = category; + this.message = String.format("[Category: %s]", + this.category); + } + + public String getCategory() { + return category; + } + + @Override + public String toString() { + return this.message; + } + + + } +} diff --git a/org.tizen.common/src/org/tizen/common/util/log/messages.properties b/org.tizen.common/src/org/tizen/common/util/log/messages.properties new file mode 100644 index 0000000..68d6113 --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/util/log/messages.properties @@ -0,0 +1,12 @@ +FileAppender_EXCEPTION_CREATING_BUFFER=Exception occurred while creating buffered writer. +FileAppender_EXCEPTION_CREATING_LOGFILE=Exception occurred while creating log file: {0}. +FileAppender_EXCEPTION_FLUSHING_BUFFER=Exception occurred while flushing buffer. +FileAppender_EXCEPTION_WRITING_LOG=Exception occurred while writing log message. +FileAppender_EXCEPTION_DIRECTORY_EXISTING=Log File {0} already exists as a directory. +LOGGER_OFF_DES=off +LOGGER_ERROR_DES=error +LOGGER_WARNING_DES=warning +LOGGER_INFO_DES=info +LOGGER_DEBUG_DES=debug +LOGGER_ALL_DES=all +UserLogger_EVENT_STRING=Category: {0}\tAction: {1} diff --git a/org.tizen.common/src/org/tizen/common/util/log/preference/Messages.java b/org.tizen.common/src/org/tizen/common/util/log/preference/Messages.java deleted file mode 100644 index 194a778..0000000 --- a/org.tizen.common/src/org/tizen/common/util/log/preference/Messages.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Common -* -* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. -* -* Contact: -* Kangho Kim -* NamKoong Ho -* -* 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. -* -* Contributors: -* - S-Core Co., Ltd -* -*/ - -package org.tizen.common.util.log.preference; - -import org.eclipse.osgi.util.NLS; -import org.tizen.common.CommonPlugin; - -public class Messages extends NLS { - - private static final String BUNDLE_NAME = CommonPlugin.PLUGIN_ID + ".util.log.preference.messages";//$NON-NLS-1$ - - private Messages() { - // Do not instantiate - } - - public static String TizenLoggerPreferencePage_Description; - public static String TizenLoggerPreferencePage_LevelGroupTitle; - - static { - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } -} diff --git a/org.tizen.common/src/org/tizen/common/util/log/preference/TizenLoggerPreferencePage.java b/org.tizen.common/src/org/tizen/common/util/log/preference/TizenLoggerPreferencePage.java deleted file mode 100644 index 424afda..0000000 --- a/org.tizen.common/src/org/tizen/common/util/log/preference/TizenLoggerPreferencePage.java +++ /dev/null @@ -1,140 +0,0 @@ -/* -* Common -* -* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. -* -* Contact: -* Kangho Kim -* NamKoong Ho -* -* 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. -* -* Contributors: -* - S-Core Co., Ltd -* -*/ - -package org.tizen.common.util.log.preference; - -import java.util.HashMap; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.preference.PreferencePage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -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.Control; -import org.eclipse.swt.widgets.Group; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPreferencePage; -import org.tizen.common.CommonPlugin; -import org.tizen.common.util.log.TizenLog4Configurator; - -public class TizenLoggerPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { - - private static final IPreferenceStore prefStore = CommonPlugin.getDefault().getPreferenceStore(); - private Button selectedButton; - public static final String OPTION_ID_LEVEL = "org.tizen.common.logger.level"; - - public static final String LEVEL_ERROR = "&Error"; - public static final String LEVEL_WARN = "&Warning"; - public static final String LEVEL_INFO = "&Info"; - public static final String LEVEL_DEBUG = "&Debug"; - - private HashMap buttonMap = new HashMap(); - private final String[] levels = {LEVEL_ERROR, LEVEL_WARN, LEVEL_INFO, LEVEL_DEBUG}; - - public TizenLoggerPreferencePage() { - setDescription(Messages.TizenLoggerPreferencePage_Description); - } - - @Override - public void init(IWorkbench workbench) { - // TODO Auto-generated method stub - } - - @Override - protected Control createContents(Composite parent) { - Composite composite = new Composite(parent, SWT.None); - composite.setLayout(new GridLayout(1, false)); - - Group levelGroup = new Group(composite, SWT.None); - levelGroup.setLayout(new GridLayout(levels.length, false)); - levelGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - levelGroup.setText(Messages.TizenLoggerPreferencePage_LevelGroupTitle); - - for(String level: levels) { - final Button radioButton = new Button(levelGroup, SWT.RADIO); - radioButton.setText(level); - buttonMap.put(level, radioButton); - radioButton.addSelectionListener(new SelectionListener() { - - @Override - public void widgetSelected(SelectionEvent e) { - selectedButton = radioButton; - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - }); - } - - String selection = prefStore.getString(OPTION_ID_LEVEL); - Button selected = buttonMap.get(selection); - - selectedButton = (selected != null) ? selected : buttonMap.get(LEVEL_ERROR); - selectedButton.setSelection(true); - - return composite; - } - - public static String getLoggerLevel() { - String level = prefStore.getString(OPTION_ID_LEVEL); - - if(level != null) { - return level; - } - - return LEVEL_ERROR; - } - - @Override - protected void performDefaults() { - selectedButton.setSelection(false); - Button defaultButton = buttonMap.get(LEVEL_ERROR); - defaultButton.setSelection(true); - selectedButton = defaultButton; - TizenLog4Configurator.setLoggerLevel(LEVEL_ERROR); - super.performDefaults(); - } - - @Override - protected void performApply() { - if(selectedButton != null) { - String selection = selectedButton.getText(); - prefStore.putValue(OPTION_ID_LEVEL, selection); - TizenLog4Configurator.setLoggerLevel(selection); - } - } - - @Override - public boolean performOk() { - performApply(); - return super.performOk(); - } - -} diff --git a/org.tizen.common/src/org/tizen/common/util/log/preference/messages.properties b/org.tizen.common/src/org/tizen/common/util/log/preference/messages.properties deleted file mode 100644 index 79ab7a8..0000000 --- a/org.tizen.common/src/org/tizen/common/util/log/preference/messages.properties +++ /dev/null @@ -1,2 +0,0 @@ -TizenLoggerPreferencePage_Description=Set the preferences about the logger -TizenLoggerPreferencePage_LevelGroupTitle=Logger Level diff --git a/org.tizen.common/test/src/org/tizen/common/util/log/FileAppenderTest.java b/org.tizen.common/test/src/org/tizen/common/util/log/FileAppenderTest.java new file mode 100644 index 0000000..d5e09a6 --- /dev/null +++ b/org.tizen.common/test/src/org/tizen/common/util/log/FileAppenderTest.java @@ -0,0 +1,224 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util.log; + +import java.io.File; +import java.io.IOException; +import static junit.framework.Assert.*; + +import org.apache.log4j.EnhancedPatternLayout; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.powermock.api.mockito.PowerMockito.*; +import org.tizen.common.util.FileUtil; +import org.tizen.common.util.StringUtil; + +public class FileAppenderTest { + + private static final String TEST_LOG_FILE_FIRST = "test1.txt"; + private static final String TEST_LOG_FILE_SECOND = "test2.txt"; + private static final String TEST_LOG_FILE_NOOP = "noop.txt"; + private static final String RESULT = "A"; + private static final String BUFFER_RESULT_FIRST = "AAAAA"; + private static final String BUFFER_RESULT_SECOND = "BBBBB"; + + private FileAppender appender; + private EnhancedPatternLayout TEST_LAYOUT = new EnhancedPatternLayout("%m"); + private LoggingEvent event; + + /** + * Sets up the test + * + * @throws Exception + */ + @Before + public void setUp() throws Exception { + File testFile = new File(TEST_LOG_FILE_FIRST); + if(testFile.exists()) { + testFile.delete(); + } + + File testFile2 = new File(TEST_LOG_FILE_SECOND); + if(testFile2.exists()) { + testFile2.delete(); + } + + appender = new FileAppender(TEST_LOG_FILE_FIRST, TEST_LAYOUT, 5); + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, RESULT, null ); + } + + /** + * + * TestCase for {@link FileAppender#append(LoggingEvent)} + * It tests timeout + * + * @author ho.namkoong (ho.namkoong@samsung.com) + * + * @throws Exception + */ + @Test + public void test_append_timeout() throws Exception { + appender.append(event); + String emptyResult = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(StringUtil.EMPTY_STRING, emptyResult); + + Thread.sleep(4000); + + String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(RESULT, result); + } + + /** + * + * TestCase for {@link FileAppender#append(LoggingEvent)} + * It tests buffer overflow + * + * @author ho.namkoong (ho.namkoong@samsung.com) + * + * @throws Exception + */ + @Test + public void test_appender_bufferover() throws Exception { + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null ); + appender.append(event); + String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(BUFFER_RESULT_FIRST, result); + + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_SECOND, null ); + appender.append(event); + result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(BUFFER_RESULT_FIRST + BUFFER_RESULT_SECOND, result); + } + + /** + * + * TestCase for {@link FileAppender#setFilePath(String)} + * + * @author ho.namkoong (ho.namkoong@samsung.com) + * + * @throws Exception + */ + @Test + public void test_setFilePath() throws Exception { + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null ); + appender.append(event); + String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(BUFFER_RESULT_FIRST, result); + + appender.setFilePath(TEST_LOG_FILE_SECOND); + + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_SECOND, null ); + appender.append(event); + result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(BUFFER_RESULT_FIRST, result); + result = FileUtil.readTextFile(new File(TEST_LOG_FILE_SECOND), null); + assertEquals(BUFFER_RESULT_SECOND, result); + } + + /** + * + * TestCase for {@link FileAppender#setBufferSize(int)} + * + * @author ho.namkoong (ho.namkoong@samsung.com) + * + * @throws Exception + */ + @Test + public void test_setBufferSize() throws Exception { + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null ); + appender.append(event); + String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(BUFFER_RESULT_FIRST, result); + + appender.setBufferSize(10); + + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_SECOND, null ); + appender.append(event); + result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(BUFFER_RESULT_FIRST, result); + + Thread.sleep(4000); + + result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null); + assertEquals(BUFFER_RESULT_FIRST + BUFFER_RESULT_SECOND, result); + } + + /** + * + * TestCase for {@link FileAppender#append(LoggingEvent)} + * It tests NOOP_OUTPUT_STREAM + * + * @author ho.namkoong (ho.namkoong@samsung.com) + * + * @throws Exception + */ + @Test + public void test_append_noop() throws Exception { + File noopFile = new File(TEST_LOG_FILE_NOOP); + + File mockFile = mock(File.class); + when(mockFile.exists()).thenReturn(false); + when(mockFile.getAbsoluteFile()).thenReturn(mockFile); + when(mockFile.getParentFile()).thenReturn(mockFile); + when(mockFile.mkdirs()).thenReturn(true); + when(mockFile.createNewFile()).thenThrow(new IOException()); + + whenNew(File.class).withArguments(TEST_LOG_FILE_NOOP).thenReturn(mockFile); + event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null ); + appender.append(event); + assertFalse(noopFile.exists()); + + } + + /** + * + * Tears down the test + * + * @author ho.namkoong (ho.namkoong@samsung.com) + * + * @throws Exception + */ + @After + public void tearDown() throws Exception { + File testFile = new File(TEST_LOG_FILE_FIRST); + if(testFile.exists()) { + testFile.delete(); + } + + File testFile2 = new File(TEST_LOG_FILE_SECOND); + if(testFile2.exists()) { + testFile2.delete(); + } + + TEST_LAYOUT.setConversionPattern("%m"); + appender = null; + } + +} diff --git a/org.tizen.common/test/src/org/tizen/common/util/log/GoogleAnalyticAppenderTest.java b/org.tizen.common/test/src/org/tizen/common/util/log/GoogleAnalyticAppenderTest.java new file mode 100644 index 0000000..f55adb8 --- /dev/null +++ b/org.tizen.common/test/src/org/tizen/common/util/log/GoogleAnalyticAppenderTest.java @@ -0,0 +1,155 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * BonYong Lee + * Ho Namkoong + * + * 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +package org.tizen.common.util.log; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; + +import static junit.framework.Assert.*; + +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.slf4j.LoggerFactory; +import org.tizen.common.util.log.UserLogger.Event; +import org.tizen.common.util.log.UserLogger.Page; +import org.tizen.common.util.log.UserLogger.PerformanceInfo; + +import static org.powermock.api.mockito.PowerMockito.*; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({GoogleAnalyticAppender.class}) +@PowerMockIgnore(value = {"org.slf4j.*", "org.apache.log4j.*"}) +public class GoogleAnalyticAppenderTest +{ + private org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass()); + private boolean connected = true; + + /** + * Sets up the test + * + * @throws Exception + */ + @Before + public void setUp() throws Exception { + final URL u = new URL( GoogleAnalyticAppender.URL_GOOGLE_ANALYTIC ); + HttpURLConnection con = null; + try { + con = (HttpURLConnection) u.openConnection(); + con.setDoOutput(true); + con.getOutputStream(); + } catch (IOException e) { + connected = false; + } + finally { + if(con != null) { + con.disconnect(); + } + } + } + + /** + * + * TestCase for {@link GoogleAnalyticAppender#append(LoggingEvent)} + * + * @author ho.namkoong (ho.namkoong@samsung.com) + * + * @throws Exception + */ + @Test + public void test_append() throws Exception + { + if(!connected) { + logger.error("Network to the google analytics is not connected"); + URL mockUrl = mock(URL.class); + HttpURLConnection mockCon = mock(HttpURLConnection.class); + OutputStream mockOutputStream = mock(OutputStream.class); + when(mockCon.getOutputStream()).thenReturn(mockOutputStream); + when(mockCon.getResponseCode()).thenReturn(200); + when(mockUrl.openConnection()).thenReturn(mockCon); + whenNew(URL.class).withArguments(GoogleAnalyticAppender.URL_GOOGLE_ANALYTIC).thenReturn(mockUrl); + OutputStreamWriter mockWriter = mock(OutputStreamWriter.class); + whenNew(OutputStreamWriter.class).withAnyArguments().thenReturn(mockWriter); + } + + final GoogleAnalyticAppender appender = new GoogleAnalyticAppender(true, true); + Logger logger = Logger.getLogger(this.getClass()); + LoggingEvent event = new LoggingEvent( null, logger, Level.ERROR, "TI", null ); + appender.append(event); + assertTrue(appender.rc >= 200 && appender.rc < 300); + + event = new LoggingEvent(null, logger, Level.PAGE, new Page("Page category"), null); + appender.append(event); + assertTrue(appender.rc >= 200 && appender.rc < 300); + appender.rc = 0; + + event = new LoggingEvent(null, logger, Level.EVENT, new Event("Event Category", "Event Action"), null); + appender.append(event); + assertTrue(appender.rc >= 200 && appender.rc < 300); + appender.rc = 0; + + long start = System.currentTimeMillis(); + event = new LoggingEvent(null, logger, Level.PERFORM_START, new PerformanceInfo("Performance category", start, 0, "Performance variable"), null); + appender.append(event); + assertTrue(appender.rc >= 200 && appender.rc < 300); + appender.rc = 0; + + long end = System.currentTimeMillis(); + event = new LoggingEvent(null, logger, Level.PERFORM_END, new PerformanceInfo("Performance category", start, end, "Performance variable"), null); + appender.append(event); + assertTrue(appender.rc >= 200 && appender.rc < 300); + appender.rc = 0; + + try { + makeException(5); + } + catch (IllegalStateException e) { + event = new LoggingEvent(null, logger, Level.ERROR, "Test Exception", e); + appender.append(event); + assertTrue(appender.rc >= 200 && appender.rc < 300); + appender.rc = 0; + } + } + + private void makeException(int i) { + if(i < 1) { + throw new IllegalStateException("Test Exception"); + } + makeException(i-1); + } + + + +} \ No newline at end of file