2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.xacml.parser;
24 import java.io.FileInputStream;
25 import java.io.FileReader;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.LineNumberReader;
29 import java.io.RandomAccessFile;
30 import java.nio.charset.Charset;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.sql.Connection;
35 import java.sql.DriverManager;
36 import java.sql.PreparedStatement;
37 import java.sql.SQLException;
38 import java.text.Format;
39 import java.text.ParseException;
40 import java.text.SimpleDateFormat;
41 import java.util.Date;
42 import java.util.Properties;
43 import java.util.Timer;
44 import java.util.regex.Matcher;
45 import java.util.regex.Pattern;
46 import java.util.stream.Stream;
48 import org.apache.log4j.Logger;
49 import org.onap.policy.common.im.AdministrativeStateException;
50 import org.onap.policy.common.im.IntegrityMonitor;
51 import org.onap.policy.common.im.StandbyStatusException;
52 import org.onap.policy.common.logging.flexlogger.FlexLogger;
53 import org.onap.policy.utils.CryptoUtils;
54 import org.onap.xacml.parser.LogEntryObject.LOGTYPE;
57 * Parse log files and store the information in a H2 database.
61 public class ParseLog {
63 // only logging last line of each log file processed to the log4j log file defined by property - PARSERLOGPATH
64 private static final Logger log4jlogger = Logger.getLogger(ParseLog.class.getName());
67 private static org.onap.policy.common.logging.flexlogger.Logger logger = FlexLogger.getLogger(ParseLog.class.getName());
69 private static String system;
70 private static int lastNumberRead = 0;
71 private static int debuglastNumberRead = 0;
72 private static int errorlastNumberRead = 0;
73 private static String type;
74 private static long startFileSize;
75 private static long debugStartFileSize;
76 private static long errorStartFileSize;
77 private static String systemLogFile;
78 private static String logFile;
79 private static String debuglogFile;
80 private static String errorlogFile;
81 private static String jdbcUrl;
82 private static String jdbcUser;
83 private static String jdbcPassword;
84 private static String jdbcDriver;
85 private static int maxLength = 255; //Max length that is allowed in the DB table
86 private static String resourceName;
87 private static long sleepTimer = 50000;
88 static IntegrityMonitor im;
89 private static boolean isMissingLogFile;
90 //Default:Timer initial delay and the delay between in milliseconds before task is to be execute
91 private static final int TIMER_DELAY_TIME = 1000;
92 //Default:Timer scheduleAtFixedRate period - time in milliseconds between successive task executions
93 private static int checkInterval = 86400000; // run this clean up once a day
94 private static String loggingProcess = "Error processing line in ";
95 private static int defaultTimeFrame = 5;
96 private static String message =" value read in: ";
97 private static String lineFormat = "(\\r\\n|\\n)";
98 private static String lineRead = "-line-Read:";
99 private static String br= "<br />";
100 private static String last = "Last-";
101 private static String breakLoop = "break the loop.";
102 private static String dateFormat = "yyyy-MM-dd HH:mm:ss";
104 public static void main(String[] args) throws Exception {
106 Properties logProperties = getPropertiesValue("parserlog.properties");
108 if(logProperties == null || isMissingLogFile){
109 // missing the path of log file in the properties file, so stop the process
110 logger.error("logProperties is null or LOGPATH is missing in parserlog.properties, so stop the process.");
114 //trigger the cleanup systemLogDb timer
117 File fileLog = new File(systemLogFile);
119 im = IntegrityMonitor.getInstance(resourceName,logProperties );
121 startDebugLogParser(fileLog);
122 startErrorLogParser(fileLog);
123 startAPIRestLogParser(fileLog);
127 private static boolean processLine(Path debugfilePath, String dataFileName, int lastNmRead, LOGTYPE logType){
128 // log4jlogger must use .info
129 try(Stream<String> lines = Files.lines(debugfilePath, Charset.defaultCharset()).onClose(() -> log4jlogger.info(last+dataFileName+ lineRead + lastNmRead)).skip(lastNmRead)){
130 lines.forEachOrdered(line -> process(line, type, logType));
131 } catch (IOException e) {
132 logger.error(loggingProcess + dataFileName, e);
133 logger.error(breakLoop);
138 private static void processDebugLogParser(File debugfile, Path debugfilePath, String dataFileName){
140 Runnable runnable = new Runnable (){
141 boolean isStop = false;
144 if (debugfile.isFile()){
145 isStop = processLine(debugfilePath, dataFileName, debuglastNumberRead, LOGTYPE.DEBUG);
148 Thread.sleep(sleepTimer);
149 debugStartFileSize = countLines(debuglogFile);
150 } catch (Exception e) {
151 logger.error(loggingProcess + dataFileName, e);
152 logger.error(breakLoop);
155 logger.debug("File Line Count of debug.log: " + debugStartFileSize + message + debuglastNumberRead);
156 if (debugStartFileSize < debuglastNumberRead ){
157 logger.debug("Failed Rolled: set Last number read to 0");
158 debuglastNumberRead = 0;
164 Thread thread = new Thread(runnable);
168 private static void startDebugLogParser(File fileLog) throws IOException{
170 if(debuglogFile != null && !debuglogFile.isEmpty()){
172 // pull the last line number
173 String dataFileName = "debug.log";
174 String filesRead = pullLastLineRead(fileLog, dataFileName);
175 if (filesRead!= null){
176 filesRead = filesRead.replaceAll(lineFormat, br);
177 debuglastNumberRead= Integer.parseInt(filesRead.trim());
179 debuglastNumberRead = 0;
182 debugStartFileSize = countLines(debuglogFile);
183 if (debugStartFileSize < debuglastNumberRead ){
184 logger.error("Filed Rolled: set Last debug number read to 0");
185 debuglastNumberRead = 0;
188 isMissingLogFile = false;
189 Path debugfilePath = Paths.get(debuglogFile);
190 File debugfile = new File(debuglogFile);
191 debugStartFileSize = debugfile.length();
193 // start process debug.log file
194 processDebugLogParser(debugfile, debugfilePath, dataFileName);
199 private static void processErrorLogParser(File errorfile, Path errorfilePath, String dataFileName){
200 Runnable runnable = new Runnable (){
201 boolean isStop = false;
205 if (errorfile.isFile()){
206 isStop = processLine(errorfilePath, dataFileName, errorlastNumberRead, LOGTYPE.ERROR);
209 Thread.sleep(sleepTimer);
210 errorStartFileSize = countLines(errorlogFile);
211 } catch (Exception e) {
212 logger.error(loggingProcess + dataFileName, e);
213 logger.error(breakLoop);
217 logger.debug("File Line Count of error.log: " + errorStartFileSize + message + errorlastNumberRead);
218 if (errorStartFileSize < errorlastNumberRead ){
219 logger.debug("Failed Rolled: set Last error number read to 0");
220 errorlastNumberRead = 0;
226 Thread thread = new Thread(runnable);
230 private static void startErrorLogParser(File fileLog) throws IOException{
232 if(errorlogFile != null && !errorlogFile.isEmpty()){
234 // pull the last line number
235 String dataFileName = "error.log";
236 String filesRead = pullLastLineRead(fileLog, dataFileName);
237 if (filesRead!= null){
238 filesRead = filesRead.replaceAll(lineFormat, br);
239 errorlastNumberRead= Integer.parseInt(filesRead.trim());
241 errorlastNumberRead = 0;
244 errorStartFileSize = countLines(errorlogFile);
245 if (errorStartFileSize < errorlastNumberRead ){
246 logger.error("Filed Rolled: set Last error number read to 0");
247 errorlastNumberRead = 0;
250 isMissingLogFile = false;
251 Path errorfilePath = Paths.get(errorlogFile);
252 File errorfile = new File(errorlogFile);
253 errorStartFileSize = errorfile.length();
254 // start process error.log file
255 processErrorLogParser(errorfile, errorfilePath, dataFileName);
260 private static void processAPIRestLog(File file, Path filePath, String dataFileName){
262 Runnable runnable = new Runnable () {
263 boolean isStop = false;
268 isStop = processLine(filePath, dataFileName, lastNumberRead, LOGTYPE.INFO);
271 Thread.sleep(sleepTimer);
272 startFileSize = countLines(logFile);
273 } catch (Exception e) {
274 logger.error(loggingProcess + dataFileName, e);
275 logger.error(breakLoop);
279 logger.debug("File Line Count of " + dataFileName+": " + startFileSize + message + lastNumberRead);
280 if (startFileSize < lastNumberRead ){
281 logger.debug("Failed Rolled: set Last number read to 0");
288 Thread thread = new Thread(runnable);
292 private static void startAPIRestLogParser(File fileLog) throws IOException{
294 if(logFile != null && !logFile.isEmpty()){
296 // pull the last line number
297 String dataFileName = type.toLowerCase()+"-rest.log";
298 String filesRead = pullLastLineRead(fileLog, dataFileName);
299 if (filesRead!= null){
300 filesRead = filesRead.replaceAll(lineFormat, br);
301 lastNumberRead= Integer.parseInt(filesRead.trim());
305 startFileSize = countLines(logFile);
306 if (startFileSize < lastNumberRead ){
307 logger.error("Filed Rolled: set Last number read to 0");
311 isMissingLogFile = false;
312 Path filePath = Paths.get(logFile);
313 File file = new File(logFile);
314 startFileSize = file.length();
315 // start process pap/pdp-rest.log file
316 processAPIRestLog(file, filePath, dataFileName);
320 public static int countLines(String filename){
323 FileReader freader = new FileReader(filename);
324 LineNumberReader reader = new LineNumberReader(freader);
327 while ((line = reader.readLine()) != null) {
328 logger.debug("Reading the Logs"+line);
330 cnt = reader.getLineNumber();
331 logger.info("Line number:"+cnt);
342 public static String pullLastLineRead(File file, String dataFileName) throws IOException {
344 file.createNewFile();
347 try(RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");){
348 StringBuilder builder = new StringBuilder();
349 long length = file.length();
350 logger.debug("dataFileName: " +dataFileName);
353 randomAccessFile.seek(length);
354 for(long seek = length; seek >= 0; --seek){
355 randomAccessFile.seek(seek);
356 char c = (char)randomAccessFile.read();
359 builder = builder.reverse();
360 logger.debug("builder.toString(): " +builder.toString());
361 if (builder.toString().contains(last+dataFileName+lineRead)){
362 String[] parseString = builder.toString().split(last+dataFileName+lineRead);
363 String returnValue = parseString[1].replace("\r", "");
364 randomAccessFile.close();
365 return returnValue.trim();
367 builder = new StringBuilder();
371 randomAccessFile.close();
376 private static LogEntryObject getDebugOutLogValue (String line, String type){
379 LogEntryObject logEntry = new LogEntryObject();
380 logEntry.setSystemType(type);
381 logEntry.setSystem(system);
382 String info1 = "||INFO||";
383 String info2 = "INFO:";
384 String error1 = "||ERROR||";
385 String error2 = "ERROR:";
387 if(line.contains(info1) || line.contains(error1) || line.contains(info2) || line.contains(error2)){
388 String[] splitString = null;
389 if(line.contains(info1) || line.contains(error1)){
390 splitString = line.split("[||]");
391 }else if(line.contains(info2)){
392 splitString = line.split(info2);
394 splitString = line.split(error2);
396 String dateString = splitString[0].substring(0, 19);
397 logEntry.setDescription(splitString[splitString.length-1]);
400 date = parseDate(dateString.replace("T", " "), dateFormat, false);
401 logEntry.setDate(date);
403 logEntry.setRemote(parseRemoteSystem(line));
404 if (line.contains(info2) || line.contains(info1)){
405 logEntry.setLogType(LOGTYPE.INFO);
407 logEntry.setLogType(LOGTYPE.ERROR);
416 private static LogEntryObject getRestAPIOutLogValue (String line, String type){
418 LogEntryObject logEntry = new LogEntryObject();
419 logEntry.setSystemType(type);
420 logEntry.setSystem(system);
421 String info3 = "INFO";
423 // from PDP/PAP rest log file below
424 if (line.contains(info3) && line.contains(")-")){
425 //parse out description
426 logEntry.setDescription(line.substring(line.indexOf(")-")+3));
428 date = parseDate(line, dateFormat, true);
429 logEntry.setDate(date);
431 logEntry.setRemote(parseRemoteSystem(line));
432 logEntry.setLogType(LOGTYPE.INFO);
440 private static LogEntryObject getInfoOutLogValue (String line, String type){
442 LogEntryObject logEntry = new LogEntryObject();
443 logEntry.setSystemType(type);
444 logEntry.setSystem(system);
445 String info3 = "INFO";
447 if (line.contains(info3) && line.contains("--- [")){
448 //parse out description
449 String temp = line.substring(line.indexOf("---")+1);
450 String[] split = temp.split(":");
452 logEntry.setDescription(split[1]);
455 date = parseDate(line, dateFormat, false);
456 logEntry.setDate(date);
459 logEntry.setRemote(parseRemoteSystem(line));
460 logEntry.setLogType(LOGTYPE.INFO);
468 private static LogEntryObject getSevereOutLogValue (String line, String type){
470 LogEntryObject logEntry = new LogEntryObject();
471 logEntry.setSystemType(type);
472 logEntry.setSystem(system);
473 if (line.contains("SEVERE") && line.contains("[main]")){
474 String[] splitString = line.split(" ");
475 StringBuilder description = new StringBuilder();
476 for (int i = 5; i < splitString.length; i++){
477 description.append(" " + splitString[i]);
480 logEntry.setDescription(description.toString());
482 date = parseDate(line, dateFormat, false);
483 logEntry.setDate(date);
484 logEntry.setLogType(LOGTYPE.SEVERE);
489 if (line.contains("ERROR") && line.contains(")-")){
490 //parse out description
491 StringBuilder description = new StringBuilder();
492 description.append(line.substring(line.indexOf(")-")+3));
494 date = parseDate(line, dateFormat, true);
495 logEntry.setDate(date);
496 logEntry.setDescription(description.toString());
498 logEntry.setRemote(parseRemoteSystem(line));
499 logEntry.setLogType(LOGTYPE.ERROR);
507 private static LogEntryObject getWarnOutLogValue (String line, String type){
509 LogEntryObject logEntry = new LogEntryObject();
510 logEntry.setSystemType(type);
511 logEntry.setSystem(system);
512 if (line.contains("WARN") && line.contains(")-")){
513 //parse out description
515 logEntry.setDescription(line.substring(line.indexOf(")-")+3));
518 date = parseDate(line, dateFormat, true);
519 logEntry.setDate(date);
522 logEntry.setRemote(parseRemoteSystem(line));
523 logEntry.setLogType(LOGTYPE.WARN);
528 if (line.contains("WARNING") && type =="PyPDP"){
529 String[] splitString = line.split(" ");
530 StringBuilder description = new StringBuilder();
532 for (int i = 5; i < splitString.length; i++){
533 description.append(" " + splitString[i]);
537 date = parseDate(line, dateFormat, false);
538 logEntry.setDate(date);
539 logEntry.setLogType(LOGTYPE.WARN);
540 logEntry.setDescription(description.toString());
547 public static LogEntryObject pullOutLogValues(String line, String type){
549 LogEntryObject logEntry = getDebugOutLogValue(line, type);
551 if(logEntry == null){
552 logEntry = getRestAPIOutLogValue(line, type);
554 if(logEntry == null){
555 logEntry = getInfoOutLogValue(line, type);
557 if(logEntry == null){
558 logEntry = getSevereOutLogValue(line, type);
560 if(logEntry == null){
561 logEntry = getWarnOutLogValue(line, type);
567 private static void dbClose(Connection conn) {
570 } catch (SQLException e) {
571 logger.error("Error closing DB Connection: " + e);
576 public static void process(String line, String type, LOGTYPE logFile) {
578 LogEntryObject returnLogValue = null;
581 im.startTransaction();
582 } catch (AdministrativeStateException e) {
583 logger.error("Error received" + e);
584 } catch (StandbyStatusException ex) {
585 logger.error("Error received" + ex);
588 returnLogValue = pullOutLogValues(line, type);
590 if(logFile.equals(LOGTYPE.DEBUG)){
591 debuglastNumberRead++;
592 }else if(logFile.equals(LOGTYPE.ERROR)){
593 errorlastNumberRead++;
594 }else if(logFile.equals(LOGTYPE.INFO)){
597 if (returnLogValue!=null){
598 writeDB(returnLogValue);
605 private static void writeDB(LogEntryObject returnLogValue) {
607 Connection conn = dbConnection(jdbcDriver, jdbcUrl, jdbcUser,jdbcPassword);
608 dbAccesss(conn, returnLogValue.getSystem(), returnLogValue.getDescription(),
609 returnLogValue.getDate(), returnLogValue.getRemote(),
610 returnLogValue.getSystemType(), returnLogValue.getLogType().toString());
614 private static Connection dbConnection(String driver, String jdbc, String user, String pass){
617 Class.forName(driver);
618 return DriverManager.getConnection(jdbc, user, pass);
619 } catch ( Exception e) {
620 logger.error("Error connecting to DB: " + e);
624 private static void dbAccesss(Connection conn, String system, String description, Date date, String remote, String type, String logType) {
628 Format formatter = new SimpleDateFormat(dateFormat);
629 sdate = formatter.format(date);
630 logger.debug("DBAccesss : sdate : " + sdate);
632 logger.debug("DBAccesss : sdate is null");
635 //ensure the length of description is less than the maximumm db char length
636 if (description.length() > maxLength) {
637 description = description.substring(0, maxLength);
641 PreparedStatement prep = conn.prepareStatement("insert into SYSTEMLOGDB values (NULL, ?, ?, ?, ?, ?, ?);");
644 prep.setString(1, system);
645 prep.setString(2, description);
646 prep.setString(3, remote);
647 prep.setString(4, type);
648 prep.setString(5, sdate);
649 prep.setString(6, logType);
651 prep.executeUpdate();
654 } catch (SQLException e1) {
655 logger.error("Error trying to excute SQL Statment: " + e1);
659 public static Date parseDate(String dateline, String pattern, boolean singleSplit) {
662 String[] splitString = dateline.split(" ");
663 SimpleDateFormat formatter = new SimpleDateFormat(pattern);
666 returnDate = formatter.parse(dateline);
667 } catch (ParseException e) {
668 logger.error("Unable to parse date for line: " + dateline);
672 String tmpString = splitString[0] + " " + splitString[1];
674 returnDate = formatter.parse(tmpString);
675 } catch (ParseException e) {
676 logger.error("Unable to parse date for line: " + dateline);
685 public static String parseRemoteSystem(String line) {
687 if (line.contains("http") && !(line.contains("www.w3.org"))){
689 Pattern pattern = Pattern.compile("://(.+?)/");
690 Matcher remote = pattern.matcher(line);
693 return remote.group(1);
699 public static String[] getPaths(String logPath){
700 String[] oneFile = null;
701 if(logPath != null && !logPath.isEmpty()){
702 if(logPath.contains(";")){
703 return logPath.split(";");
705 oneFile = new String[1];
706 oneFile[0] = logPath;
713 private static void setCleanUpProperties(String cleanupInterval, String timeFrame){
714 if(cleanupInterval != null && !cleanupInterval.isEmpty()){
715 int intCheckInterval = Integer.parseInt(cleanupInterval);
716 if(intCheckInterval > 300000) {//must be longer than 5 minutes
717 checkInterval = intCheckInterval;
720 logger.debug("No value defined for CHECK_INTERVAL in parserlog.properties, so use its default value:" + checkInterval + " milliseconds");
723 if(timeFrame != null && !timeFrame.trim().isEmpty()){
724 int intTimeFrame = defaultTimeFrame;
726 intTimeFrame = Integer.parseInt(timeFrame);
727 }catch(NumberFormatException e){
728 logger.debug("Improper value defined for TIME_FRAME in parserlog.properties, so use its default value:" + defaultTimeFrame + " days");
730 if(intTimeFrame > 0){
731 defaultTimeFrame = intTimeFrame;
734 logger.debug("No value defined for TIME_FRAME in parserlog.properties, so use its default value:" + defaultTimeFrame + " days");
738 private static void setDebuglogFile(String fileName){
739 debuglogFile = fileName;
740 if(debuglogFile != null && !debuglogFile.isEmpty()){
741 debuglogFile = debuglogFile.trim();
747 private static void setErrorlogFile(String fileName){
748 errorlogFile = fileName;
749 if(errorlogFile != null && !errorlogFile.isEmpty()){
750 errorlogFile = errorlogFile.trim();
756 private static void setLogFileProperties(String[] splitString){
757 if(splitString != null){
758 for(int i=0; i < splitString.length; i++){
760 if(splitString[i].contains("debug")){
761 // get path of debug.log file
762 setDebuglogFile(splitString[i]);
763 }else if(splitString[i].contains("error")){
764 // get path of error.log file
765 setErrorlogFile(splitString[i]);
767 // get path of default file
768 logFile = splitString[i];
769 if(logFile != null && !logFile.isEmpty()){
770 logFile = logFile.trim();
779 public static Properties getPropertiesValue(String fileName) {
780 Properties config = new Properties();
781 Path file = Paths.get(fileName);
782 if (file.toFile().exists()) {
784 if (file.toString().endsWith(".properties")) {
787 in = new FileInputStream(file.toFile());
790 resourceName = config.getProperty("RESOURCE_NAME");
791 system = config.getProperty("SERVER");
792 type = config.getProperty("LOGTYPE");
793 systemLogFile = config.getProperty("PARSERLOGPATH");
794 String logFiles = config.getProperty("LOGPATH");
795 String cleanupInterval= config.getProperty("CHECK_INTERVAL");
796 String timeFrame = config.getProperty("TIME_FRAME");
798 setCleanUpProperties(cleanupInterval, timeFrame);
800 if(logFiles == null || logFiles.isEmpty()){
801 isMissingLogFile = true;
805 String[] splitString = getPaths(logFiles);
807 setLogFileProperties(splitString);
809 jdbcUrl = config.getProperty("JDBC_URL").replace("'", "");
810 jdbcUser = config.getProperty("JDBC_USER");
811 jdbcDriver = config.getProperty("JDBC_DRIVER");
812 jdbcPassword = CryptoUtils.decryptTxtNoExStr(config.getProperty("JDBC_PASSWORD", ""));
813 config.setProperty("javax.persistence.jdbc.password", CryptoUtils.decryptTxtNoExStr(config.getProperty("javax.persistence.jdbc.password", "")));
816 } catch (IOException e) {
817 logger.error("Error porcessing Config file will be unable to create Health Check" + e);
819 logger.error("Error getPropertiesValue on TIME_FRAME", e);
820 logger.debug("Error getPropertiesValue on TIME_FRAME, so use its default value:" + defaultTimeFrame + " days");
826 logger.debug("File doesn't exist in the specified Path " + file.toString());
831 public static Connection getDbConnection(){
832 return dbConnection(jdbcDriver, jdbcUrl, jdbcUser,jdbcPassword);
834 private static void startCleanUp(){
835 Connection conn = dbConnection(jdbcDriver, jdbcUrl, jdbcUser,jdbcPassword);
836 CleanUpSystemLogDB cleanUp = new CleanUpSystemLogDB(conn, defaultTimeFrame);
837 Timer timer = new Timer(true);
838 timer.scheduleAtFixedRate(cleanUp, TIMER_DELAY_TIME, checkInterval);
839 logger.info("startCleanUp begins! : " + new Date());