1 40 41 package org.dspace.app.statistics; 42 43 import java.io.BufferedReader ; 44 import java.io.File ; 45 import java.io.FileOutputStream ; 46 import java.io.FileReader ; 47 import java.io.IOException ; 48 import java.io.OutputStreamWriter ; 49 import java.io.PrintWriter ; 50 import java.sql.SQLException ; 51 import java.text.ParseException ; 52 import java.text.SimpleDateFormat ; 53 import java.util.ArrayList ; 54 import java.util.Arrays ; 55 import java.util.Calendar ; 56 import java.util.Date ; 57 import java.util.GregorianCalendar ; 58 import java.util.HashMap ; 59 import java.util.Iterator ; 60 import java.util.List ; 61 import java.util.Map ; 62 import java.util.StringTokenizer ; 63 import java.util.regex.Matcher ; 64 import java.util.regex.Pattern ; 65 66 import org.dspace.content.DCValue; 67 import org.dspace.content.Item; 68 import org.dspace.core.ConfigurationManager; 69 import org.dspace.core.Context; 70 import org.dspace.handle.HandleManager; 71 72 82 public class ReportGenerator 83 { 84 86 90 91 private static Map actionAggregator = new HashMap (); 92 93 94 private static Map searchAggregator = new HashMap (); 95 96 97 private static Map userAggregator = new HashMap (); 98 99 100 private static Map itemAggregator = new HashMap (); 101 102 103 private static Map archiveStats = new HashMap (); 104 105 106 110 111 private static int searchFloor; 112 113 114 private static int itemFloor; 115 116 117 private static int itemLookup; 118 119 120 private static String userEmail; 121 122 123 private static String url; 124 125 126 private static String name; 127 128 129 private static int avgItemViews; 130 131 132 private static String serverName; 133 134 135 private static Date startDate = null; 136 137 138 private static Date endDate = null; 139 140 141 private static int processTime; 142 143 144 private static int logLines; 145 146 147 private static int warnings; 148 149 150 private static List generalSummary = new ArrayList (); 151 152 156 157 private static Pattern real = Pattern.compile("^(.+)=(.+)"); 158 159 163 164 private static Calendar startTime = null; 165 166 167 private static Map actionMap = new HashMap (); 168 169 173 174 private static String format = null; 175 176 177 private static String input = null; 178 179 180 private static String output = ConfigurationManager.getProperty("dspace.dir") + 181 File.separator + "log" + File.separator + "report"; 182 183 184 private static String map = ConfigurationManager.getProperty("dspace.dir") + 185 File.separator + "config" + File.separator + "dstat.map"; 186 187 188 192 public static void main(String [] argv) 193 throws Exception , SQLException 194 { 195 Context context = new Context(); 197 context.setIgnoreAuthorization(true); 198 199 String myFormat = null; 200 String myInput = null; 201 String myOutput = null; 202 String myMap = null; 203 204 for (int i = 0; i < argv.length; i++) 206 { 207 if (argv[i].equals("-format")) 208 { 209 myFormat = argv[i+1].toLowerCase(); 210 } 211 212 if (argv[i].equals("-in")) 213 { 214 myInput = argv[i+1]; 215 } 216 217 if (argv[i].equals("-out")) 218 { 219 myOutput = argv[i+1]; 220 } 221 222 if (argv[i].equals("-map")) 223 { 224 myMap = argv[i+1]; 225 } 226 227 if (argv[i].equals("-help")) 228 { 229 usage(); 230 System.exit(0); 231 } 232 } 233 234 processReport(context, myFormat, myInput, myOutput, myMap); 235 } 236 237 247 public static void processReport(Context context, String myFormat, 248 String myInput, String myOutput, 249 String myMap) 250 throws Exception , SQLException 251 { 252 startTime = new GregorianCalendar (); 253 254 setParameters(myFormat, myInput, myOutput, myMap); 256 257 FileReader fr = null; 259 BufferedReader br = null; 260 261 readInput(input); 263 264 readMap(map); 266 267 Report report = null; 270 if (format.equals("html")) 271 { 272 report = new HTMLReport(); 273 } 274 275 report.setStartDate(startDate); 276 report.setEndDate(endDate); 277 report.setMainTitle(name, serverName); 278 279 Iterator keys = null; 282 int i = 0; 283 String explanation = null; 284 int value; 285 286 289 Statistics overview = new Statistics(); 290 291 overview.setSectionHeader("General Overview"); 292 293 Iterator summaryEntries = generalSummary.iterator(); 294 while (summaryEntries.hasNext()) 295 { 296 String entry = (String ) summaryEntries.next(); 297 if (actionAggregator.containsKey(entry)) 298 { 299 int count = Integer.parseInt((String ) actionAggregator.get(entry)); 300 overview.add(new Stat(translate(entry), count)); 301 } 302 } 303 304 report.addBlock(overview); 305 306 if (archiveStats.size() > 0) 308 { 309 Statistics archiveInfo = prepareStats(archiveStats, true, false); 310 archiveInfo.setSectionHeader("Archive Information"); 311 archiveInfo.setStatName("Content Type"); 312 archiveInfo.setResultName("Number of items"); 313 314 report.addBlock(archiveInfo); 315 } 316 317 318 319 Statistics viewedItems = new Statistics("Item/Handle", "Number of views", itemFloor); 323 viewedItems.setSectionHeader("Items Viewed"); 324 325 Stat[] items = new Stat[itemAggregator.size()]; 326 327 keys = itemAggregator.keySet().iterator(); 328 i = 0; 329 while (keys.hasNext()) 330 { 331 String key = (String ) keys.next(); 332 String link = url + "handle/" + key; 333 value = Integer.parseInt((String ) itemAggregator.get(key)); 334 items[i] = new Stat(key, value, link); 335 i++; 336 } 337 338 Arrays.sort(items); 339 340 String info = null; 341 for (i = 0; i < items.length; i++) 342 { 343 if (i < itemLookup) 344 { 345 info = getItemInfo(context, items[i].getKey()); 346 } 347 348 if (info != null) 351 { 352 items[i].setKey(info + " (" + items[i].getKey() + ")"); 353 } 354 else 355 { 356 items[i].setKey(items[i].getReference()); 357 } 358 359 info = null; 361 } 362 363 viewedItems.add(items); 364 365 report.addBlock(viewedItems); 366 367 Statistics fullInfo = prepareStats(actionAggregator, true, true); 369 fullInfo.setSectionHeader("All Actions Performed"); 370 fullInfo.setStatName("Action"); 371 fullInfo.setResultName("Number of times"); 372 373 report.addBlock(fullInfo); 374 375 if (!userEmail.equals("off")) 377 { 378 Statistics userLogins = prepareStats(userAggregator, true, false); 379 userLogins.setSectionHeader("User Logins"); 380 userLogins.setStatName("User"); 381 userLogins.setResultName("Number of logins"); 382 if (userEmail.equals("alias")) 383 { 384 explanation = "(distinct addresses)"; 385 userLogins.setExplanation(explanation); 386 } 387 388 report.addBlock(userLogins); 389 } 390 391 Statistics searchWords = prepareStats(searchAggregator, true, false); 393 searchWords.setSectionHeader("Words Searched"); 394 searchWords.setStatName("Word"); 395 searchWords.setResultName("Number of searches"); 396 searchWords.setFloor(searchFloor); 397 398 report.addBlock(searchWords); 399 400 if (avgItemViews > 0) 405 { 406 Statistics avg = new Statistics(); 407 avg.setSectionHeader("Averaging Information"); 408 409 Stat[] average = new Stat[1]; 410 411 average[0] = new Stat("Average views per item", avgItemViews); 412 avg.add(average); 413 report.addBlock(avg); 414 } 415 416 417 Statistics levels = new Statistics("Level", "Number of lines"); 421 levels.setSectionHeader("Log Level Information"); 422 423 Stat[] level = new Stat[1]; 424 level[0] = new Stat("Warnings", warnings); 425 426 levels.add(level); 427 428 report.addBlock(levels); 429 430 Calendar endTime = new GregorianCalendar (); 432 long timeInMillis = (endTime.getTimeInMillis() - startTime.getTimeInMillis()); 433 int outputProcessTime = (new Long (timeInMillis).intValue() / 1000); 434 435 Statistics process = new Statistics("Operation", ""); 437 process.setSectionHeader("Processing Information"); 438 439 Stat[] proc = new Stat[3]; 440 proc[0] = new Stat("Log Processing Time", processTime); 441 proc[0].setUnits("seconds"); 442 proc[1] = new Stat("Output Processing Time", outputProcessTime); 443 proc[1].setUnits("seconds"); 444 proc[2] = new Stat("Log File Lines Analysed", logLines); 445 proc[2].setUnits("lines"); 446 447 process.add(proc); 448 449 report.addBlock(process); 450 451 try 453 { 454 FileOutputStream fos = new FileOutputStream (output); 455 OutputStreamWriter osr = new OutputStreamWriter (fos, "UTF-8"); 456 PrintWriter out = new PrintWriter (osr); 457 out.write(report.render()); 458 out.close(); 459 } 460 catch (IOException e) 461 { 462 System.out.println("Unable to write to output file " + output); 463 System.exit(0); 464 } 465 466 return; 467 } 468 469 470 482 public static Statistics prepareStats(Map aggregator, boolean sort, boolean translate) 483 { 484 Stat[] stats = new Stat[aggregator.size()]; 485 if (aggregator.size() > 0) 486 { 487 Iterator keys = aggregator.keySet().iterator(); 488 int i = 0; 489 while (keys.hasNext()) 490 { 491 String key = (String ) keys.next(); 492 int value = Integer.parseInt((String ) aggregator.get(key)); 493 if (translate) 494 { 495 stats[i] = new Stat(translate(key), value); 496 } 497 else 498 { 499 stats[i] = new Stat(key, value); 500 } 501 i++; 502 } 503 504 if (sort) 505 { 506 Arrays.sort(stats); 507 } 508 } 509 510 Statistics statistics = new Statistics(); 512 statistics.add(stats); 513 514 return statistics; 515 } 516 517 518 528 public static String translate(String text) 529 { 530 if (actionMap.containsKey(text)) 531 { 532 return (String ) actionMap.get(text); 533 } 534 else 535 { 536 return text; 537 } 538 } 539 540 541 547 public static void readMap(String map) 548 throws IOException 549 { 550 FileReader fr = null; 551 BufferedReader br = null; 552 553 String record = null; 555 try 556 { 557 fr = new FileReader (map); 558 br = new BufferedReader (fr); 559 } 560 catch (IOException e) 561 { 562 System.err.println("Failed to read map file: log file actions will be displayed without translation"); 563 return; 564 } 565 566 while ((record = br.readLine()) != null) 568 { 569 Matcher matchReal = real.matcher(record); 570 571 if (matchReal.matches()) 573 { 574 actionMap.put(matchReal.group(1).trim(), matchReal.group(2).trim()); 575 } 576 } 577 } 578 579 580 591 public static void setParameters(String myFormat, String myInput, 592 String myOutput, String myMap) 593 { 594 if (myFormat != null) 595 { 596 format = myFormat; 597 } 598 599 if (myInput != null) 600 { 601 input = myInput; 602 } 603 604 if (myOutput != null) 605 { 606 output = myOutput; 607 } 608 609 if (myMap != null) 610 { 611 map = myMap; 612 } 613 614 return; 615 } 616 617 618 624 public static void readInput(String input) 625 throws IOException , ParseException 626 { 627 FileReader fr = null; 628 BufferedReader br = null; 629 630 String record = null; 633 try 634 { 635 fr = new FileReader (input); 636 br = new BufferedReader (fr); 637 } 638 catch (IOException e) 639 { 640 System.out.println("Failed to read input file"); 641 System.exit(0); 642 } 643 644 while ((record = br.readLine()) != null) 647 { 648 Matcher matchReal = real.matcher(record); 650 651 String section = null; 653 String key = null; 654 String value = null; 655 656 String left = null; 658 659 if (matchReal.matches()) 661 { 662 left = matchReal.group(1).trim(); 664 value = matchReal.group(2).trim(); 665 666 StringTokenizer tokens = new StringTokenizer (left, "."); 670 int numTokens = tokens.countTokens(); 671 if (tokens.hasMoreTokens()) 672 { 673 section = tokens.nextToken(); 674 if (numTokens > 1) 675 { 676 key = left.substring(section.length() + 1); 677 } 678 else 679 { 680 key = ""; 681 } 682 } 683 } 684 else 685 { 686 continue; 687 } 688 689 691 SimpleDateFormat sdf = new SimpleDateFormat ("dd'/'MM'/'yyyy"); 694 695 if (section.equals("archive")) 697 { 698 archiveStats.put(key, value); 699 } 700 701 if (section.equals("action")) 702 { 703 actionAggregator.put(key, value); 704 } 705 706 if (section.equals("user")) 707 { 708 userAggregator.put(key, value); 709 } 710 711 if (section.equals("search")) 712 { 713 searchAggregator.put(key, value); 714 } 715 716 if (section.equals("item")) 717 { 718 itemAggregator.put(key, value); 719 } 720 721 if (section.equals("user_email")) 723 { 724 userEmail = value; 725 } 726 727 if (section.equals("item_floor")) 728 { 729 itemFloor = Integer.parseInt(value); 730 } 731 732 if (section.equals("search_floor")) 733 { 734 searchFloor = Integer.parseInt(value); 735 } 736 737 if (section.equals("host_url")) 738 { 739 url = value; 740 } 741 742 if (section.equals("item_lookup")) 743 { 744 itemLookup = Integer.parseInt(value); 745 } 746 747 if (section.equals("avg_item_views")) 748 { 749 try 750 { 751 avgItemViews = Integer.parseInt(value); 752 } 753 catch (NumberFormatException e) 754 { 755 avgItemViews = 0; 756 } 757 } 758 759 if (section.equals("server_name")) 760 { 761 serverName = value; 762 } 763 764 if (section.equals("service_name")) 765 { 766 name = value; 767 } 768 769 if (section.equals("start_date")) 770 { 771 startDate = sdf.parse(value); 772 } 773 774 if (section.equals("end_date")) 775 { 776 endDate = sdf.parse(value); 777 } 778 779 if (section.equals("analysis_process_time")) 780 { 781 processTime = Integer.parseInt(value); 782 } 783 784 if (section.equals("general_summary")) 785 { 786 generalSummary.add(value); 787 } 788 789 if (section.equals("log_lines")) 790 { 791 logLines = Integer.parseInt(value); 792 } 793 794 if (section.equals("warnings")) 795 { 796 warnings = Integer.parseInt(value); 797 } 798 } 799 800 br.close(); 802 fr.close(); 803 } 804 805 815 public static String getItemInfo(Context context, String handle) 816 throws SQLException 817 { 818 Item item = null; 819 820 try 822 { 823 item = (Item) HandleManager.resolveToObject(context, handle); 824 } 825 catch (Exception e) 826 { 827 return null; 828 } 829 830 if (item == null) 832 { 833 return null; 834 } 835 836 DCValue[] title = item.getDC("title", null, Item.ANY); 840 DCValue[] author = item.getDC("contributor", "author", Item.ANY); 841 842 StringBuffer authors = new StringBuffer (); 843 if (author.length > 0) 844 { 845 authors.append("(" + author[0].value); 846 } 847 if (author.length > 1) 848 { 849 authors.append(" et al"); 850 } 851 if (author.length > 0) 852 { 853 authors.append(")"); 854 } 855 856 String content = title[0].value + " " + authors.toString(); 857 858 return content; 859 } 860 861 862 865 public static void usage() 866 { 867 String usage = "Usage Information:\n" + 868 "ReportGenerator [options [parameters]]\n" + 869 "-format [output format]\n" + 870 "\tRequired\n" + 871 "\tSpecify the format that you would like the output in\n" + 872 "\tOptions:\n" + 873 "\t\thtml\n" + 874 "-in [aggregation file]\n" + 875 "\tRequired\n" + 876 "\tSpecify the aggregation data file to display\n" + 877 "-out [output file]\n" + 878 "\tOptional\n" + 879 "\tSpecify the file to output the report to\n" + 880 "\tDefault uses [dspace log directory]/report\n" + 881 "-map [map file]\n" + 882 "\tOptional\n" + 883 "\tSpecify the map file to translate log file actions into human readable actions\n" + 884 "\tDefault uses [dspace config directory]/dstat.map\n" + 885 "-help\n" + 886 "\tdisplay this usage information\n"; 887 888 System.out.println(usage); 889 } 890 } 891 | Popular Tags |