Issue #2359 initial checkin of remote log service
Change-Id: Idd48062f204002956f63c6d449868a7bd9695263 Former-commit-id:3162ae260b
[formerly3162ae260b
[formerly 12988c63aeccc678f25f4210ad484a080ddd8aa7]] Former-commit-id:f148663bd1
Former-commit-id:ebf89475c5
This commit is contained in:
parent
d64d1ffad3
commit
d70275ed1c
22 changed files with 2071 additions and 0 deletions
7
javaUtilities/com.raytheon.uf.logsrv/.classpath
Normal file
7
javaUtilities/com.raytheon.uf.logsrv/.classpath
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
28
javaUtilities/com.raytheon.uf.logsrv/.project
Normal file
28
javaUtilities/com.raytheon.uf.logsrv/.project
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.raytheon.uf.logsrv</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,7 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
15
javaUtilities/com.raytheon.uf.logsrv/META-INF/MANIFEST.MF
Normal file
15
javaUtilities/com.raytheon.uf.logsrv/META-INF/MANIFEST.MF
Normal file
|
@ -0,0 +1,15 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Logsrv
|
||||
Bundle-SymbolicName: com.raytheon.uf.logsrv
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Activator: com.raytheon.uf.logsrv.Activator
|
||||
Bundle-Vendor: RAYTHEON
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: ch.qos.logback;bundle-version="1.0.13",
|
||||
org.slf4j;bundle-version="1.7.5",
|
||||
org.apache.derby;bundle-version="10.10.1",
|
||||
javax.mail,
|
||||
org.quartz;bundle-version="1.8.6",
|
||||
org.apache.commons.lang;bundle-version="2.3.0"
|
4
javaUtilities/com.raytheon.uf.logsrv/build.properties
Normal file
4
javaUtilities/com.raytheon.uf.logsrv/build.properties
Normal file
|
@ -0,0 +1,4 @@
|
|||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
11
javaUtilities/com.raytheon.uf.logsrv/config.xml
Normal file
11
javaUtilities/com.raytheon.uf.logsrv/config.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<logSrvConfig>
|
||||
<clusterName>ts1-oma</clusterName>
|
||||
<databaseDir>/awips2/edex/data/utility/nate</databaseDir>
|
||||
<fromAddress>Nathan.Jensen@raytheon.com</fromAddress>
|
||||
<smtpHost>mk2-msg10.raymail.ray.com</smtpHost>
|
||||
<smtpPort>143</smtpPort>
|
||||
<!-- toAddress>awipsctl@list.app.ray.com</toAddress-->
|
||||
<toAddress>Nathan.Jensen@raytheon.com</toAddress>
|
||||
<timeToSend>01:30</timeToSend>
|
||||
</logSrvConfig>
|
13
javaUtilities/com.raytheon.uf.logsrv/derby.log
Normal file
13
javaUtilities/com.raytheon.uf.logsrv/derby.log
Normal file
|
@ -0,0 +1,13 @@
|
|||
----------------------------------------------------------------
|
||||
Wed Sep 11 15:37:35 CDT 2013:
|
||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.10.1.1 - (1458268): instance a816c00e-0141-0ebe-4f2c-000009e7d350
|
||||
on database directory /awips2/edex/data/utility/nate with class loader sun.misc.Launcher$AppClassLoader@4aad3ba4
|
||||
Loaded from file:/common/njensen/git/development/cots/org.apache.derby/derby.jar
|
||||
java.vendor=Sun Microsystems Inc.
|
||||
java.runtime.version=1.6.0_43-b01
|
||||
user.dir=/common/njensen/git/development/javaUtilities/com.raytheon.uf.logsrv
|
||||
os.name=Linux
|
||||
os.arch=amd64
|
||||
os.version=2.6.18-238.el5
|
||||
derby.system.home=null
|
||||
Database Class Loader started - derby.database.classpath=''
|
48
javaUtilities/com.raytheon.uf.logsrv/receiver.xml
Normal file
48
javaUtilities/com.raytheon.uf.logsrv/receiver.xml
Normal file
|
@ -0,0 +1,48 @@
|
|||
<configuration debug="true">
|
||||
|
||||
<appender name="DERBY" class="com.raytheon.uf.logsrv.derby.DerbyAppender">
|
||||
</appender>
|
||||
|
||||
<appender name="InternalLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>/home/njensen/logs/logService-internal-%d{yyyyMMdd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%-5p %d [%t] %c{0}: %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-5p %d [%t] %c{0}: %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="asyncConsole" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="console" />
|
||||
</appender>
|
||||
|
||||
<appender name="InternalLogAsync" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="InternalLog" />
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="InternalLogger" additivity="false">
|
||||
<level value="INFO"/>
|
||||
<appender-ref ref="asyncConsole" />
|
||||
<appender-ref ref="InternalLogAsync" />
|
||||
</logger>
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="DERBY" />
|
||||
</root>
|
||||
|
||||
<receiver class="ch.qos.logback.classic.net.server.ServerSocketReceiver">
|
||||
<address>dev33.oma.us.ray.com</address>
|
||||
<port>5477</port>
|
||||
</receiver>
|
||||
|
||||
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.joran.JoranConfigurator;
|
||||
|
||||
import com.raytheon.uf.logsrv.config.LogSrvConfig;
|
||||
import com.raytheon.uf.logsrv.derby.DerbyDao;
|
||||
import com.raytheon.uf.logsrv.quartz.JobScheduler;
|
||||
|
||||
/**
|
||||
* The main class of the logging service that loads the config files and
|
||||
* therefore listens for incoming logging events.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 27, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class LogService {
|
||||
|
||||
private static final String LOGBACK_CONFIG = "receiver.xml";
|
||||
|
||||
private static final String SERVICE_CONFIG = "config.xml";
|
||||
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger("InternalLogger");
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
logger.info("Starting log analytics service");
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance(LogSrvConfig.class);
|
||||
Unmarshaller m = context.createUnmarshaller();
|
||||
LogSrvConfig config = (LogSrvConfig) m.unmarshal(new File(
|
||||
SERVICE_CONFIG));
|
||||
config.validate();
|
||||
DerbyDao.setConfig(config);
|
||||
logger.info("Logging events from " + config.getClusterName());
|
||||
|
||||
logger.info("Starting socket listener");
|
||||
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
lc.reset();
|
||||
JoranConfigurator configurator = new JoranConfigurator();
|
||||
configurator.setContext(lc);
|
||||
configurator.doConfigure(LOGBACK_CONFIG);
|
||||
|
||||
logger.info("Scheduling report generation");
|
||||
JobScheduler.scheduleJobs(config);
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv;
|
||||
|
||||
/**
|
||||
* An exception in the logging service.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 27, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class LogServiceException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*
|
||||
*/
|
||||
public LogServiceException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
public LogServiceException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
*/
|
||||
public LogServiceException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
*/
|
||||
public LogServiceException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.classic.spi.IThrowableProxy;
|
||||
import ch.qos.logback.classic.spi.StackTraceElementProxy;
|
||||
import ch.qos.logback.classic.spi.ThrowableProxyUtil;
|
||||
|
||||
/**
|
||||
* A translation of a logging event to a POJO that closely resembles what is in
|
||||
* the database.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 27, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class StoredMsg {
|
||||
|
||||
private Date eventTime;
|
||||
|
||||
private String message;
|
||||
|
||||
private String javaClass;
|
||||
|
||||
private int lineNumber;
|
||||
|
||||
// TODO build date or build number? not sure how to get logback to send that
|
||||
// along
|
||||
|
||||
private String stacktrace;
|
||||
|
||||
private String threadName;
|
||||
|
||||
private String machineName;
|
||||
|
||||
private String level;
|
||||
|
||||
public StoredMsg(ILoggingEvent event) {
|
||||
eventTime = new Date(event.getTimeStamp());
|
||||
|
||||
// find the most underlying cause
|
||||
IThrowableProxy cause = event.getThrowableProxy();
|
||||
if (cause != null) {
|
||||
stacktrace = ThrowableProxyUtil.asString(cause);
|
||||
while (cause.getCause() != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
|
||||
message = cause.getMessage();
|
||||
StackTraceElementProxy[] stack = cause
|
||||
.getStackTraceElementProxyArray();
|
||||
if (stack != null && stack.length > 0) {
|
||||
StackTraceElement ste = stack[0].getStackTraceElement();
|
||||
lineNumber = ste.getLineNumber();
|
||||
javaClass = ste.getClassName();
|
||||
}
|
||||
} else {
|
||||
message = event.getMessage();
|
||||
}
|
||||
threadName = event.getThreadName();
|
||||
machineName = event.getLoggerContextVO().getPropertyMap()
|
||||
.get("HOSTNAME");
|
||||
level = event.getLevel().toString();
|
||||
|
||||
}
|
||||
|
||||
public Date getEventTime() {
|
||||
return eventTime;
|
||||
}
|
||||
|
||||
public void setEventTime(Date eventTime) {
|
||||
this.eventTime = eventTime;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getJavaClass() {
|
||||
return javaClass;
|
||||
}
|
||||
|
||||
public void setJavaClass(String javaClass) {
|
||||
this.javaClass = javaClass;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
public void setLineNumber(int lineNumber) {
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public String getThreadName() {
|
||||
return threadName;
|
||||
}
|
||||
|
||||
public void setThreadName(String threadName) {
|
||||
this.threadName = threadName;
|
||||
}
|
||||
|
||||
public String getMachineName() {
|
||||
return machineName;
|
||||
}
|
||||
|
||||
public void setMachineName(String machineName) {
|
||||
this.machineName = machineName;
|
||||
}
|
||||
|
||||
public String getStacktrace() {
|
||||
return stacktrace;
|
||||
}
|
||||
|
||||
public void setStacktrace(String stacktrace) {
|
||||
this.stacktrace = stacktrace;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StoredMsg [eventTime=" + eventTime + ", message=" + message
|
||||
+ ", javaClass=" + javaClass + ", lineNumber=" + lineNumber
|
||||
+ ", stacktrace=" + stacktrace + ", threadName=" + threadName
|
||||
+ ", machineName=" + machineName + ", level=" + level + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.config;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
/**
|
||||
* A configuration for the logging service.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 29, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
public class LogSrvConfig {
|
||||
|
||||
@XmlElement()
|
||||
private String clusterName;
|
||||
|
||||
@XmlElement
|
||||
private String databaseDir;
|
||||
|
||||
@XmlElement
|
||||
private String fromAddress;
|
||||
|
||||
@XmlElement
|
||||
private String smtpHost;
|
||||
|
||||
@XmlElement
|
||||
private int smtpPort;
|
||||
|
||||
@XmlElement
|
||||
private String toAddress;
|
||||
|
||||
@XmlElement
|
||||
private String timeToSend;
|
||||
|
||||
public String getFromAddress() {
|
||||
return fromAddress;
|
||||
}
|
||||
|
||||
public void setFromAddress(String fromAddress) {
|
||||
this.fromAddress = fromAddress;
|
||||
}
|
||||
|
||||
public String getSmtpHost() {
|
||||
return smtpHost;
|
||||
}
|
||||
|
||||
public void setSmtpHost(String smtpHost) {
|
||||
this.smtpHost = smtpHost;
|
||||
}
|
||||
|
||||
public int getSmtpPort() {
|
||||
return smtpPort;
|
||||
}
|
||||
|
||||
public void setSmtpPort(int smtpPort) {
|
||||
this.smtpPort = smtpPort;
|
||||
}
|
||||
|
||||
public String getToAddress() {
|
||||
return toAddress;
|
||||
}
|
||||
|
||||
public void setToAddress(String toAddress) {
|
||||
this.toAddress = toAddress;
|
||||
}
|
||||
|
||||
public String getClusterName() {
|
||||
return clusterName;
|
||||
}
|
||||
|
||||
public void setClusterName(String clusterName) {
|
||||
this.clusterName = clusterName;
|
||||
}
|
||||
|
||||
public String getTimeToSend() {
|
||||
return timeToSend;
|
||||
}
|
||||
|
||||
public void setTimeToSend(String timeToSend) {
|
||||
this.timeToSend = timeToSend;
|
||||
}
|
||||
|
||||
public String getDatabaseDir() {
|
||||
return databaseDir;
|
||||
}
|
||||
|
||||
public void setDatabaseDir(String databaseDir) {
|
||||
this.databaseDir = databaseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the config has every value set.
|
||||
*/
|
||||
public void validate() {
|
||||
Validate.notEmpty(clusterName, "Config must include a clusterName");
|
||||
Validate.notEmpty(databaseDir, "Config must include a databaseDir");
|
||||
Validate.notEmpty(fromAddress, "Config must include a fromAddress");
|
||||
Validate.notEmpty(smtpHost, "Config must include an smtpHost");
|
||||
Validate.notEmpty(timeToSend, "Config must include a timeToSend");
|
||||
Validate.notEmpty(toAddress, "Config must include a toAddress");
|
||||
if (smtpPort <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Config must include an smtpPort");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.derby;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
|
||||
import com.raytheon.uf.logsrv.LogService;
|
||||
import com.raytheon.uf.logsrv.LogServiceException;
|
||||
import com.raytheon.uf.logsrv.StoredMsg;
|
||||
|
||||
/**
|
||||
* A logback appender that stores a logging event to the database.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 27, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class DerbyAppender extends AppenderBase<ILoggingEvent> {
|
||||
|
||||
@Override
|
||||
protected void append(ILoggingEvent eventObject) {
|
||||
StoredMsg msg = new StoredMsg(eventObject);
|
||||
try {
|
||||
DerbyDao.getInstance().insert(msg);
|
||||
} catch (LogServiceException e) {
|
||||
LogService.getLogger().error(
|
||||
"Error inserting message into derby database", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,536 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.derby;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import com.raytheon.uf.logsrv.LogService;
|
||||
import com.raytheon.uf.logsrv.LogServiceException;
|
||||
import com.raytheon.uf.logsrv.StoredMsg;
|
||||
import com.raytheon.uf.logsrv.config.LogSrvConfig;
|
||||
import com.raytheon.uf.logsrv.report.data.LogReportContainer;
|
||||
import com.raytheon.uf.logsrv.report.data.LogReportEvent;
|
||||
|
||||
/**
|
||||
* DAO for interacting with the derby database to add rows or create report
|
||||
* objects.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 27, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class DerbyDao {
|
||||
|
||||
private static final String DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
|
||||
|
||||
private static final String TABLE = "log";
|
||||
|
||||
private static final String DB_CREATE = "CREATE TABLE " + TABLE
|
||||
+ "(pk INT NOT NULL GENERATED BY DEFAULT AS IDENTITY, "
|
||||
+ "eventTime TIMESTAMP, " + "message VARCHAR(32672), "
|
||||
+ "javaClass VARCHAR(128), " + "lineNumber INT, "
|
||||
+ "stacktrace VARCHAR(32672), " + "threadName VARCHAR(128), "
|
||||
+ "machineName VARCHAR(128), " + "level VARCHAR(32))";
|
||||
|
||||
private static final String INSERT_PREPARED_STATEMENT = "INSERT INTO "
|
||||
+ TABLE
|
||||
+ "(eventTime, message, javaClass, lineNumber, stacktrace, threadName, machineName, level) "
|
||||
+ "values (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String PURGE_STATEMENT = "DELETE from " + TABLE;
|
||||
|
||||
private static final String TIME_STATEMENT = "select min(eventTime), max(eventTime) FROM "
|
||||
+ TABLE;
|
||||
|
||||
private static final String COUNT_STATEMENT = "select count(*) from "
|
||||
+ TABLE;
|
||||
|
||||
private PreparedStatement saveStatement;
|
||||
|
||||
private PreparedStatement purgeStatement;
|
||||
|
||||
private PreparedStatement timeStatement;
|
||||
|
||||
private PreparedStatement countStatement;
|
||||
|
||||
private Connection connection;
|
||||
|
||||
private static DerbyDao instance = new DerbyDao();
|
||||
|
||||
private static LogSrvConfig config;
|
||||
|
||||
private DerbyDao() {
|
||||
|
||||
}
|
||||
|
||||
public static DerbyDao getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void setConfig(LogSrvConfig cfg) {
|
||||
config = cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection to derby
|
||||
*
|
||||
* @return
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
private Connection createConnection() throws LogServiceException {
|
||||
Statement statement = null;
|
||||
boolean errorOccurred = false;
|
||||
Connection connection = null;
|
||||
try {
|
||||
Class.forName(DRIVER).newInstance();
|
||||
connection = DriverManager.getConnection("jdbc:derby:directory:"
|
||||
+ config.getDatabaseDir() + ";create=true");
|
||||
DatabaseMetaData dmd = connection.getMetaData();
|
||||
ResultSet tables = dmd.getTables(null, null, null,
|
||||
new String[] { "TABLE" });
|
||||
boolean needCreation = true;
|
||||
|
||||
while (tables.next()) {
|
||||
String tableName = tables.getString("TABLE_NAME");
|
||||
if (tableName.equalsIgnoreCase(TABLE)) {
|
||||
needCreation = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needCreation) {
|
||||
statement = connection.createStatement();
|
||||
statement.execute(DB_CREATE);
|
||||
}
|
||||
connection.commit();
|
||||
} catch (Exception e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException("Error setting up database", e);
|
||||
} finally {
|
||||
closeStatement(statement);
|
||||
if (errorOccurred) {
|
||||
closeConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a StoredMsg as a row in the database table
|
||||
*
|
||||
* @param event
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
public synchronized void insert(StoredMsg event) throws LogServiceException {
|
||||
boolean errorOccurred = false;
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = getConnection();
|
||||
if (saveStatement == null) {
|
||||
saveStatement = conn
|
||||
.prepareStatement(INSERT_PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
saveStatement.setTimestamp(1, new Timestamp(event.getEventTime()
|
||||
.getTime()));
|
||||
saveStatement.setString(2, event.getMessage());
|
||||
saveStatement.setString(3, event.getJavaClass());
|
||||
saveStatement.setInt(4, event.getLineNumber());
|
||||
saveStatement.setString(5, event.getStacktrace());
|
||||
saveStatement.setString(6, event.getThreadName());
|
||||
saveStatement.setString(7, event.getMachineName());
|
||||
saveStatement.setString(8, event.getLevel());
|
||||
int result = saveStatement.executeUpdate();
|
||||
if (result < 1) {
|
||||
errorOccurred = true;
|
||||
LogService.getLogger().error("Insert of logging event failed");
|
||||
} else {
|
||||
conn.commit();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException(
|
||||
"Error inserting event into log database", e);
|
||||
} finally {
|
||||
if (errorOccurred) {
|
||||
closeStatement(saveStatement);
|
||||
saveStatement = null;
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cached connection to the database
|
||||
*
|
||||
* @return
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
private synchronized Connection getConnection() throws LogServiceException {
|
||||
if (connection != null) {
|
||||
try {
|
||||
if (connection.isClosed()) {
|
||||
closeConnection(connection);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new LogServiceException("Error closing connection", e);
|
||||
}
|
||||
}
|
||||
if (connection == null) {
|
||||
try {
|
||||
connection = createConnection();
|
||||
} catch (Exception e) {
|
||||
throw new LogServiceException("Error creating connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a statement
|
||||
*
|
||||
* @param statement
|
||||
*/
|
||||
private void closeStatement(Statement statement) {
|
||||
if (statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection to the database
|
||||
*
|
||||
* @param connection
|
||||
*/
|
||||
private void closeConnection(Connection connection) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
connection = null;
|
||||
}
|
||||
|
||||
try {
|
||||
DriverManager.getConnection("jdbc:derby:directory:"
|
||||
+ config.getDatabaseDir() + ";shutdown=true");
|
||||
} catch (SQLException e) {
|
||||
// ignore as stop database will always throw an exception
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a result set
|
||||
*
|
||||
* @param rs
|
||||
*/
|
||||
private void closeResultSet(ResultSet rs) {
|
||||
if (rs != null) {
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for rows that include stacktraces and correlates them into a
|
||||
* LogReportContainer
|
||||
*
|
||||
* @return
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
private LogReportContainer queryEventsWithStacks()
|
||||
throws LogServiceException {
|
||||
Connection conn = null;
|
||||
boolean errorOccurred = false;
|
||||
Statement statement = null;
|
||||
ResultSet rs = null;
|
||||
LogReportContainer container = new LogReportContainer();
|
||||
try {
|
||||
conn = getConnection();
|
||||
statement = conn.createStatement();
|
||||
// line number of 0 indicates that there was no stacktrace with
|
||||
// the error, those will be handled separately
|
||||
rs = statement
|
||||
.executeQuery("select javaClass, lineNumber, machineName, count(*) "
|
||||
+ "from log where lineNumber != 0 "
|
||||
+ "group by javaClass, lineNumber, machineName");
|
||||
conn.commit();
|
||||
while (rs.next()) {
|
||||
String javaClass = rs.getString(1);
|
||||
int lineNumber = rs.getInt(2);
|
||||
String machineName = rs.getString(3);
|
||||
int count = rs.getInt(4);
|
||||
LogReportEvent occ = new LogReportEvent();
|
||||
// errors sent in without a stacktrace will not have a line
|
||||
// number of java class
|
||||
occ.setJavaClass(javaClass);
|
||||
occ.setLineNumber(lineNumber);
|
||||
container.addError(occ, machineName, count);
|
||||
}
|
||||
return container;
|
||||
} catch (SQLException e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException("Error executing query", e);
|
||||
} finally {
|
||||
closeResultSet(rs);
|
||||
closeStatement(statement);
|
||||
if (errorOccurred) {
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through the LogReportContainer's events and queries for sample
|
||||
* stacktraces and messages for them.
|
||||
*
|
||||
* @param container
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
private void addSamples(LogReportContainer container)
|
||||
throws LogServiceException {
|
||||
for (LogReportEvent event : container.getEvents()) {
|
||||
addSamples(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in a LogReportEvent with a sample stacktrace and message
|
||||
*
|
||||
* @param event
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
private void addSamples(LogReportEvent event) throws LogServiceException {
|
||||
Connection conn = null;
|
||||
boolean errorOccurred = false;
|
||||
Statement statement = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
conn = getConnection();
|
||||
statement = conn.createStatement();
|
||||
statement.setFetchSize(1);
|
||||
statement.setMaxRows(1);
|
||||
rs = statement.executeQuery("select message, stacktrace, level "
|
||||
+ "from log where javaClass ='" + event.getJavaClass()
|
||||
+ "' and lineNumber = " + event.getLineNumber());
|
||||
conn.commit();
|
||||
while (rs.next()) {
|
||||
String message = rs.getString(1);
|
||||
String stacktrace = rs.getString(2);
|
||||
String level = rs.getString(3);
|
||||
event.setSampleMessage(message);
|
||||
event.setSampleStacktrace(stacktrace);
|
||||
event.setLevel(level);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException("Error executing query", e);
|
||||
} finally {
|
||||
closeResultSet(rs);
|
||||
closeStatement(statement);
|
||||
if (errorOccurred) {
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for rows that don't have stacktraces and adds them to the
|
||||
* LogReportContainer
|
||||
*
|
||||
* @param container
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
private void addNoStacktraceMessages(LogReportContainer container)
|
||||
throws LogServiceException {
|
||||
Connection conn = null;
|
||||
boolean errorOccurred = false;
|
||||
Statement statement = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
conn = getConnection();
|
||||
statement = conn.createStatement();
|
||||
rs = statement
|
||||
.executeQuery("select message, machineName, level, threadName, count(*) from log "
|
||||
+ "where lineNumber = 0 group by message, machineName, level, threadName");
|
||||
conn.commit();
|
||||
while (rs.next()) {
|
||||
String message = rs.getString(1);
|
||||
String machineName = rs.getString(2);
|
||||
String level = rs.getString(3);
|
||||
String thread = rs.getString(4);
|
||||
int count = rs.getInt(5);
|
||||
LogReportEvent event = new LogReportEvent();
|
||||
event.setSampleMessage(message);
|
||||
event.setLevel(level);
|
||||
event.setThreadName(thread);
|
||||
container.addError(event, machineName, count);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException("Error executing query", e);
|
||||
} finally {
|
||||
closeResultSet(rs);
|
||||
closeStatement(statement);
|
||||
if (errorOccurred) {
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for the earliest and latest time in the database and sets them on
|
||||
* the LogReportContainer
|
||||
*
|
||||
* @param container
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
private void addTimes(LogReportContainer container)
|
||||
throws LogServiceException {
|
||||
boolean errorOccurred = false;
|
||||
Connection conn = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
conn = getConnection();
|
||||
if (timeStatement == null) {
|
||||
timeStatement = conn.prepareStatement(TIME_STATEMENT);
|
||||
}
|
||||
rs = timeStatement.executeQuery();
|
||||
conn.commit();
|
||||
rs.next();
|
||||
container.setEarliestTime(rs.getTimestamp(1));
|
||||
container.setLatestTime(rs.getTimestamp(2));
|
||||
} catch (Exception e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException(
|
||||
"Error determining min and max times", e);
|
||||
} finally {
|
||||
closeResultSet(rs);
|
||||
if (errorOccurred) {
|
||||
closeStatement(timeStatement);
|
||||
timeStatement = null;
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a LogReportContainer that correlates different rows as the same
|
||||
* event, fills in sample stacktraces and messages, and includes the
|
||||
* earliest and latest times of the events.
|
||||
*
|
||||
* @return
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
public LogReportContainer buildReport() throws LogServiceException {
|
||||
LogReportContainer container = queryEventsWithStacks();
|
||||
addSamples(container);
|
||||
addNoStacktraceMessages(container);
|
||||
addTimes(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all rows from the database
|
||||
*
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
public void clearEntries() throws LogServiceException {
|
||||
boolean errorOccurred = false;
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = getConnection();
|
||||
if (purgeStatement == null) {
|
||||
purgeStatement = conn.prepareStatement(PURGE_STATEMENT);
|
||||
}
|
||||
purgeStatement.executeUpdate();
|
||||
conn.commit();
|
||||
} catch (Exception e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException("Error purging message database", e);
|
||||
} finally {
|
||||
if (errorOccurred) {
|
||||
closeStatement(purgeStatement);
|
||||
purgeStatement = null;
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the database to determine the number of rows
|
||||
*
|
||||
* @return
|
||||
* @throws LogServiceException
|
||||
*/
|
||||
public int getCurrentRowCount() throws LogServiceException {
|
||||
boolean errorOccurred = false;
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = getConnection();
|
||||
if (countStatement == null) {
|
||||
countStatement = conn.prepareStatement(COUNT_STATEMENT);
|
||||
}
|
||||
ResultSet rs = countStatement.executeQuery();
|
||||
conn.commit();
|
||||
rs.next();
|
||||
return rs.getInt(1);
|
||||
} catch (Exception e) {
|
||||
errorOccurred = true;
|
||||
throw new LogServiceException("Error determining row count", e);
|
||||
} finally {
|
||||
if (errorOccurred) {
|
||||
closeStatement(countStatement);
|
||||
countStatement = null;
|
||||
closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.quartz;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
import com.raytheon.uf.logsrv.LogService;
|
||||
import com.raytheon.uf.logsrv.LogServiceException;
|
||||
import com.raytheon.uf.logsrv.derby.DerbyDao;
|
||||
|
||||
/**
|
||||
* A simple quartz job that logs how many log events are currently in the
|
||||
* database.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Sep 5, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class CountRowsJob implements Job {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
|
||||
*/
|
||||
@Override
|
||||
public void execute(JobExecutionContext arg0) throws JobExecutionException {
|
||||
try {
|
||||
int rowCount = DerbyDao.getInstance().getCurrentRowCount();
|
||||
LogService.getLogger()
|
||||
.info("Database currently has " + rowCount
|
||||
+ " messages reported");
|
||||
} catch (LogServiceException e) {
|
||||
LogService.getLogger().error(
|
||||
"Error determining database row count", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.quartz;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
import com.raytheon.uf.logsrv.LogService;
|
||||
import com.raytheon.uf.logsrv.LogServiceException;
|
||||
import com.raytheon.uf.logsrv.config.LogSrvConfig;
|
||||
import com.raytheon.uf.logsrv.derby.DerbyDao;
|
||||
import com.raytheon.uf.logsrv.report.data.LogReportContainer;
|
||||
import com.raytheon.uf.logsrv.report.email.HtmlGenerator;
|
||||
import com.raytheon.uf.logsrv.report.email.ReportEmailer;
|
||||
|
||||
/**
|
||||
* A quartz job that queries the database to build report data, transforms the
|
||||
* report data into HTML, emails the HTML to the configured address, and then
|
||||
* purges the database of all logging events that were included in the report.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 30, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class CreateSendReportJob implements Job {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
|
||||
*/
|
||||
@Override
|
||||
public void execute(JobExecutionContext ctx) throws JobExecutionException {
|
||||
LogService.getLogger().info(
|
||||
"Create report job triggered, preparing to send report");
|
||||
DerbyDao dao = DerbyDao.getInstance();
|
||||
// synchronize on dao to prevent new log entries from being added
|
||||
// while we're querying and then purging
|
||||
synchronized (dao) {
|
||||
LogReportContainer container = null;
|
||||
try {
|
||||
container = dao.buildReport();
|
||||
} catch (LogServiceException e) {
|
||||
LogService.getLogger().error("Error building report", e);
|
||||
throw new JobExecutionException("Error building report", e);
|
||||
}
|
||||
|
||||
String html = HtmlGenerator.generateHtml(container);
|
||||
LogSrvConfig config = (LogSrvConfig) ctx.getJobDetail()
|
||||
.getJobDataMap().get("config");
|
||||
|
||||
try {
|
||||
ReportEmailer.email(html, config);
|
||||
} catch (Exception e) {
|
||||
LogService.getLogger().error("Error emailing report", e);
|
||||
throw new JobExecutionException("Error emailing report", e);
|
||||
}
|
||||
LogService.getLogger().info(
|
||||
"Report has been sent to: " + config.getToAddress());
|
||||
|
||||
// only clear out the database if the analysis report was
|
||||
// successfully emailed
|
||||
LogService.getLogger().info(
|
||||
"Purging database of messages that were just reported");
|
||||
try {
|
||||
dao.clearEntries();
|
||||
} catch (LogServiceException e) {
|
||||
LogService.getLogger().error("Error purging database", e);
|
||||
throw new JobExecutionException("Error purging database", e);
|
||||
}
|
||||
LogService.getLogger().info("Database purging complete");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.quartz;
|
||||
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.SchedulerFactory;
|
||||
import org.quartz.Trigger;
|
||||
import org.quartz.TriggerUtils;
|
||||
import org.quartz.impl.StdSchedulerFactory;
|
||||
|
||||
import com.raytheon.uf.logsrv.config.LogSrvConfig;
|
||||
|
||||
/**
|
||||
* Schedules the quartz jobs in the main log process so at timed intervals, the
|
||||
* number of logging events in the db are reported and the error report is
|
||||
* generated and emailed.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 30, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class JobScheduler {
|
||||
|
||||
public static void scheduleJobs(LogSrvConfig config)
|
||||
throws SchedulerException {
|
||||
SchedulerFactory factory = new StdSchedulerFactory();
|
||||
Scheduler sched = factory.getScheduler();
|
||||
sched.start();
|
||||
|
||||
JobDetail job = new JobDetail("Create and Send Report Job",
|
||||
CreateSendReportJob.class);
|
||||
job.getJobDataMap().put("config", config);
|
||||
String[] split = config.getTimeToSend().split(":");
|
||||
int hour = Integer.parseInt(split[0]);
|
||||
int minute = Integer.parseInt(split[1]);
|
||||
Trigger trigger = TriggerUtils.makeDailyTrigger(hour, minute);
|
||||
trigger.setName("Report Trigger");
|
||||
sched.scheduleJob(job, trigger);
|
||||
|
||||
JobDetail countJob = new JobDetail("Count Rows Job", CountRowsJob.class);
|
||||
Trigger countTrigger = TriggerUtils.makeHourlyTrigger();
|
||||
countTrigger.setName("Count Trigger");
|
||||
sched.scheduleJob(countJob, countTrigger);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.report;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
|
||||
import com.raytheon.uf.logsrv.config.LogSrvConfig;
|
||||
import com.raytheon.uf.logsrv.derby.DerbyDao;
|
||||
import com.raytheon.uf.logsrv.report.data.LogReportContainer;
|
||||
import com.raytheon.uf.logsrv.report.email.HtmlGenerator;
|
||||
import com.raytheon.uf.logsrv.report.email.ReportEmailer;
|
||||
|
||||
/**
|
||||
* A simple main that generates a report based on the current entries in the
|
||||
* database, emails the report, and then clears the database. Allows skipping
|
||||
* waiting for the once a day email.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 28, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class TestReportOutputter {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
JAXBContext context = JAXBContext.newInstance(LogSrvConfig.class);
|
||||
Unmarshaller m = context.createUnmarshaller();
|
||||
LogSrvConfig config = (LogSrvConfig) m
|
||||
.unmarshal(new File("config.xml"));
|
||||
config.validate();
|
||||
DerbyDao.setConfig(config);
|
||||
LogReportContainer container = DerbyDao.getInstance().buildReport();
|
||||
String report = HtmlGenerator.generateHtml(container);
|
||||
ReportEmailer.email(report, config);
|
||||
DerbyDao.getInstance().clearEntries();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.report.data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A container that holds a concept of a report based on the frequency of
|
||||
* occurrences of logging events (ie errors) in the database.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 28, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class LogReportContainer {
|
||||
|
||||
private Map<String, LogReportEvent> map = new HashMap<String, LogReportEvent>();
|
||||
|
||||
private Timestamp earliestTime;
|
||||
|
||||
private Timestamp latestTime;
|
||||
|
||||
public void addError(LogReportEvent event, String machineName,
|
||||
int occurrences) {
|
||||
String key = event.getKey();
|
||||
if (!map.containsKey(key)) {
|
||||
map.put(key, event);
|
||||
}
|
||||
|
||||
LogReportEvent current = map.get(key);
|
||||
Map<String, Integer> machineCount = current.getMachineCount();
|
||||
Integer count = machineCount.get(machineName);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
count += occurrences;
|
||||
machineCount.put(machineName, count);
|
||||
}
|
||||
|
||||
public Collection<LogReportEvent> getEvents() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
public Timestamp getEarliestTime() {
|
||||
return earliestTime;
|
||||
}
|
||||
|
||||
public void setEarliestTime(Timestamp earliestTime) {
|
||||
this.earliestTime = earliestTime;
|
||||
}
|
||||
|
||||
public Timestamp getLatestTime() {
|
||||
return latestTime;
|
||||
}
|
||||
|
||||
public void setLatestTime(Timestamp latestTime) {
|
||||
this.latestTime = latestTime;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.report.data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
/**
|
||||
* An event representing a unique error that was originally reported as a
|
||||
* logging event, with a count of occurrences per machine.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 28, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class LogReportEvent implements Comparable<LogReportEvent> {
|
||||
|
||||
private int lineNumber;
|
||||
|
||||
private String javaClass;
|
||||
|
||||
private String sampleStacktrace;
|
||||
|
||||
private Map<String, Integer> machineCount = new HashMap<String, Integer>();
|
||||
|
||||
private String sampleMessage;
|
||||
|
||||
private String level;
|
||||
|
||||
private String threadName;
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
public void setLineNumber(int lineNumber) {
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public String getJavaClass() {
|
||||
return javaClass;
|
||||
}
|
||||
|
||||
public void setJavaClass(String javaClass) {
|
||||
this.javaClass = javaClass;
|
||||
}
|
||||
|
||||
public String getSampleStacktrace() {
|
||||
return sampleStacktrace;
|
||||
}
|
||||
|
||||
public void setSampleStacktrace(String sampleStacktrace) {
|
||||
this.sampleStacktrace = sampleStacktrace;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getMachineCount() {
|
||||
return machineCount;
|
||||
}
|
||||
|
||||
public void setMachineCount(Map<String, Integer> machineCount) {
|
||||
this.machineCount = machineCount;
|
||||
}
|
||||
|
||||
public String getSampleMessage() {
|
||||
return sampleMessage;
|
||||
}
|
||||
|
||||
public void setSampleMessage(String sampleMessage) {
|
||||
this.sampleMessage = sampleMessage;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public boolean receivedStack() {
|
||||
return lineNumber > 0;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
String key = null;
|
||||
if (receivedStack()) {
|
||||
key = javaClass + ":" + lineNumber;
|
||||
} else {
|
||||
key = sampleMessage;
|
||||
if (key == null) {
|
||||
key = "null";
|
||||
} else if (key.length() > 20) {
|
||||
// cut off the key to try and match it to others
|
||||
key = key.substring(0, 20);
|
||||
}
|
||||
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getTotalOccurences() {
|
||||
int count = 0;
|
||||
for (Integer i : machineCount.values()) {
|
||||
count += i;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the LogReportEvents to enable sorting. Sort order goes as
|
||||
* follows: warn, no stacktraces, and least number of occurrences error, no
|
||||
* stacktraces, and least number of occurrences stacktrace, warn, and least
|
||||
* number of occurrences stacktrace, error, and least number of occurrences
|
||||
*
|
||||
* For example, the highest/last in the sort would be the ERROR with a
|
||||
* stacktrace that occurred the most.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(LogReportEvent o) {
|
||||
int retVal = 0;
|
||||
if (!this.receivedStack() && o.receivedStack()) {
|
||||
retVal = -1;
|
||||
} else if (this.receivedStack() && !o.receivedStack()) {
|
||||
retVal = 1;
|
||||
} else {
|
||||
// both match on having a stacktrace or not, rank them
|
||||
// based on error or warning
|
||||
Level thisLevel = Level.valueOf(level);
|
||||
Level oLevel = Level.valueOf(o.getLevel());
|
||||
if (thisLevel.toInt() < oLevel.toInt()) {
|
||||
retVal = -1;
|
||||
} else if (thisLevel.toInt() > oLevel.toInt()) {
|
||||
retVal = 1;
|
||||
} else {
|
||||
// both match on having a stacktrace or not, and match
|
||||
// on being WARNs or ERRORs, so rank them on number
|
||||
// of times they occurred
|
||||
int count1 = this.getTotalOccurences();
|
||||
int count2 = o.getTotalOccurences();
|
||||
retVal = (count1 < count2) ? -1 : ((count1 == count2) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public String getThreadName() {
|
||||
return threadName;
|
||||
}
|
||||
|
||||
public void setThreadName(String threadName) {
|
||||
this.threadName = threadName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.report.email;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.raytheon.uf.logsrv.report.data.LogReportContainer;
|
||||
import com.raytheon.uf.logsrv.report.data.LogReportEvent;
|
||||
|
||||
/**
|
||||
* Uses a LogReportContainer to generate an HTML report that can be emailed.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 28, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class HtmlGenerator {
|
||||
|
||||
private static final int MAX_ERRORS = 100;
|
||||
|
||||
private static final String LINE_BREAK = "<BR/>";
|
||||
|
||||
private static final String HR = "<HR/>";
|
||||
|
||||
private static final SimpleDateFormat SDF = new SimpleDateFormat(
|
||||
"yyyy-MM-dd HH:mm z");
|
||||
|
||||
/**
|
||||
* Generates an HTML string based on the report container
|
||||
*
|
||||
* @param container
|
||||
* the container of events to generate HTML for
|
||||
* @return an HTML formatted report
|
||||
*/
|
||||
public static String generateHtml(LogReportContainer container) {
|
||||
String report = null;
|
||||
if (container != null) {
|
||||
Collection<LogReportEvent> collection = container.getEvents();
|
||||
LogReportEvent[] array = collection.toArray(new LogReportEvent[0]);
|
||||
Arrays.sort(array, Collections.reverseOrder());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(buildHeader(array.length, container.getEarliestTime(),
|
||||
container.getLatestTime()));
|
||||
sb.append(LINE_BREAK);
|
||||
boolean foundFirstWithoutStacktrace = false;
|
||||
for (int i = 0; i < array.length && i < MAX_ERRORS; i++) {
|
||||
LogReportEvent event = array[i];
|
||||
if (!event.receivedStack() && !foundFirstWithoutStacktrace) {
|
||||
foundFirstWithoutStacktrace = true;
|
||||
sb.append(buildNoStacktraceDisclaimer());
|
||||
}
|
||||
sb.append(HR);
|
||||
sb.append(LINE_BREAK);
|
||||
sb.append(buildEvent(array[i]));
|
||||
sb.append(LINE_BREAK);
|
||||
sb.append(LINE_BREAK);
|
||||
}
|
||||
report = sb.toString();
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
private static CharSequence buildHeader(int distinctErrors, Date earliest,
|
||||
Date latest) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Auto-generated error report");
|
||||
sb.append(LINE_BREAK);
|
||||
sb.append("Created on ");
|
||||
sb.append(SDF.format(new Date()));
|
||||
sb.append(LINE_BREAK);
|
||||
if (distinctErrors > 0) {
|
||||
sb.append("Timeframe of errors: <span style=\"font-style:italic;\">");
|
||||
sb.append(SDF.format(earliest));
|
||||
sb.append("</span>");
|
||||
sb.append(" to <span style=\"font-style:italic;\">");
|
||||
sb.append(SDF.format(latest));
|
||||
sb.append("</span>");
|
||||
sb.append(LINE_BREAK);
|
||||
}
|
||||
sb.append("Number of distinct errors reported: <span style=\"font-weight:bold;\">");
|
||||
sb.append(distinctErrors);
|
||||
sb.append("</span>");
|
||||
sb.append(LINE_BREAK);
|
||||
if (distinctErrors > MAX_ERRORS) {
|
||||
sb.append("Report truncated to top ");
|
||||
sb.append(MAX_ERRORS);
|
||||
sb.append(" errors/warnings");
|
||||
sb.append(LINE_BREAK);
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static CharSequence buildEvent(LogReportEvent event) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<span style=\"font-weight:bold;\">");
|
||||
sb.append(event.getLevel());
|
||||
if (!event.receivedStack()) {
|
||||
// thread name is really only useful if we don't have a stacktrace
|
||||
sb.append(" [");
|
||||
sb.append(event.getThreadName());
|
||||
sb.append("]");
|
||||
}
|
||||
sb.append(" ");
|
||||
sb.append(event.getSampleMessage());
|
||||
sb.append("</span>");
|
||||
sb.append(LINE_BREAK);
|
||||
sb.append("Occurred a total of <span style=\"font-weight:bold;\">");
|
||||
sb.append(event.getTotalOccurences());
|
||||
sb.append("</span> times on the following machines:");
|
||||
sb.append(LINE_BREAK);
|
||||
Map<String, Integer> machineCount = event.getMachineCount();
|
||||
Set<Entry<String, Integer>> set = machineCount.entrySet();
|
||||
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(
|
||||
set);
|
||||
// sort it so the machines with the most errors are listed first
|
||||
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
|
||||
@Override
|
||||
public int compare(Entry<String, Integer> o1,
|
||||
Entry<String, Integer> o2) {
|
||||
int val1 = o1.getValue();
|
||||
int val2 = o2.getValue();
|
||||
return (val2 < val1) ? -1 : ((val1 == val2) ? 0 : 1);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
for (Entry<String, Integer> entry : list) {
|
||||
sb.append("<span style=\"font-style:italic; padding-left: 30px;\">");
|
||||
sb.append(entry.getKey());
|
||||
sb.append("</span>: ");
|
||||
sb.append(entry.getValue());
|
||||
sb.append(" occurrences");
|
||||
sb.append(LINE_BREAK);
|
||||
}
|
||||
sb.append(LINE_BREAK);
|
||||
if (event.receivedStack()) {
|
||||
sb.append(event.getSampleStacktrace().replaceAll("\n", LINE_BREAK));
|
||||
}
|
||||
sb.append(LINE_BREAK);
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static CharSequence buildNoStacktraceDisclaimer() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(LINE_BREAK);
|
||||
sb.append(HR);
|
||||
sb.append("<b>Disclaimer</b>: The following errors were received without stacktraces and...");
|
||||
sb.append("<ul><li>Are estimated/inexact</li>");
|
||||
sb.append("<li>Should be considered for downgrade to INFO or DEBUG messages");
|
||||
sb.append("<li>Should include stacktraces if remaining as ERROR</li></ul>");
|
||||
return sb;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.logsrv.report.email;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import com.raytheon.uf.logsrv.config.LogSrvConfig;
|
||||
|
||||
/**
|
||||
* Emails a report using the options specified in the config.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 29, 2013 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class ReportEmailer {
|
||||
|
||||
/**
|
||||
* Emails the provided string, using the options from the config.
|
||||
*
|
||||
* @param report
|
||||
* the text to email
|
||||
* @param config
|
||||
* the config of email options
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void email(String report, LogSrvConfig config)
|
||||
throws Exception {
|
||||
Properties props = new Properties();
|
||||
props.put("host", config.getSmtpHost());
|
||||
props.put("mail.smtp.user", config.getFromAddress());
|
||||
props.put("port", config.getSmtpPort());
|
||||
|
||||
Session session = Session.getDefaultInstance(props, null);
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
message.setFrom(new InternetAddress(config.getFromAddress()));
|
||||
String[] split = config.getToAddress().split(",");
|
||||
for (String to : split) {
|
||||
message.addRecipient(Message.RecipientType.TO, new InternetAddress(
|
||||
to.trim()));
|
||||
}
|
||||
message.setSubject(config.getClusterName() + " error report");
|
||||
message.setContent(report, "text/html; charset=utf-8");
|
||||
Transport transport = session.getTransport("smtp");
|
||||
transport.connect(config.getSmtpHost(), config.getFromAddress(), null);
|
||||
transport.sendMessage(message, message.getAllRecipients());
|
||||
transport.close();
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue