All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.util.SolrLogPostTool Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.util;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.net.URLDecoder;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;
import org.apache.solr.handler.component.ShardRequest;



/**
*  A command line tool for indexing Solr logs in the out-of-the-box log format.
**/

public class SolrLogPostTool {

  public static void main(String[] args) throws Exception {

    if(args.length != 2) {
      System.out.println("");
      System.out.println("postlogs is a simple tool for indexing Solr logs.");
      System.out.println("");
      System.out.println("parameters:");
      System.out.println("");
      System.out.println("-- baseUrl: Example http://localhost:8983/solr/collection1");
      System.out.println("-- rootDir: All files found at or below the root will be indexed.");
      System.out.println("");
      System.out.println("Sample syntax 1: ./bin/postlogs http://localhost:8983/solr/collection1 /user/foo/logs/solr.log");
      System.out.println("Sample syntax 2: ./bin/postlogs http://localhost:8983/solr/collection1 /user/foo/logs");
      System.out.println("");
      return;
    }

    String baseUrl = args[0];
    String root = args[1];

    HttpSolrClient.Builder builder = new HttpSolrClient.Builder();
    SolrClient client = null;
    try {
      client = builder.withBaseSolrUrl(baseUrl).build();
      File rf = new File(root);
      List files = new ArrayList<>();
      gatherFiles(rf, files);
      int rec = 0;
      UpdateRequest request = new UpdateRequest();

      for (File file : files) {

        LineNumberReader bufferedReader = null;

        try {
          bufferedReader = new LineNumberReader(new InputStreamReader(new FileInputStream(file), Charset.defaultCharset()));
          LogRecordReader recordReader = new LogRecordReader(bufferedReader);
          SolrInputDocument doc = null;
          String fileName = file.getName();
          while (true) {
            try {
              doc = recordReader.readRecord();
            } catch (Throwable t) {
              System.err.println("Error reading log record:"+ bufferedReader.getLineNumber() +" from file:"+ fileName);
              System.err.println(t.getMessage());
              continue;
            }

            if(doc == null) {
              break;
            }

            rec++;
            UUID id = UUID.randomUUID();
            doc.setField("id", id.toString());
            doc.setField("file_s", fileName);
            request.add(doc);
            if (rec == 300) {
              sendBatch(client, request, false /* normal batch */);
              request = new UpdateRequest();
              rec = 0;
            }
          }
        } finally {
          bufferedReader.close();
        }
      }

      if (rec > 0) {
        sendBatch(client, request, true /* last batch */);
      }
    } finally {
      client.close();
    }
  }

  private static void sendBatch(SolrClient client, UpdateRequest request, boolean lastRequest) throws SolrServerException, IOException {
    final String beginMessage = lastRequest ? "Sending last batch ..." : "Sending batch of 300 log records...";
    System.out.println(beginMessage);
    try {
      request.process(client);
      System.out.println("Batch sent");
    } catch (Exception e) {
      System.err.println("Batch sending failed: " + e.getMessage());
      e.printStackTrace(System.err);
    }

    if (lastRequest) {
      try {
        client.commit();
        System.out.println("Committed");
      } catch (Exception e) {
        System.err.println("Unable to commit documents: " + e.getMessage());
        e.printStackTrace(System.err);
      }
    }
  }

  static void gatherFiles(File rootFile, List files) {

    if(rootFile.isFile()) {
      files.add(rootFile);
    } else {
      File[] subFiles = rootFile.listFiles();
      for(File f : subFiles) {
        if(f.isFile()) {
          files.add(f);
        } else {
          gatherFiles(f, files);
        }
      }
    }
  }

  public static class LogRecordReader {

    private BufferedReader bufferedReader;
    private String pushedBack = null;
    private boolean finished = false;
    private String cause;
    private Pattern p = Pattern.compile("^(\\d\\d\\d\\d\\-\\d\\d\\-\\d\\d[\\s|T]\\d\\d:\\d\\d\\:\\d\\d.\\d\\d\\d)");
    private Pattern minute = Pattern.compile("^(\\d\\d\\d\\d\\-\\d\\d\\-\\d\\d[\\s|T]\\d\\d:\\d\\d)");
    private Pattern tenSecond = Pattern.compile("^(\\d\\d\\d\\d\\-\\d\\d\\-\\d\\d[\\s|T]\\d\\d:\\d\\d:\\d)");



    public LogRecordReader(BufferedReader bufferedReader) throws IOException {
      this.bufferedReader = bufferedReader;
    }

    public SolrInputDocument readRecord() throws IOException {
      while(true) {
        String line = null;

        if(finished) {
          return null;
        }

        if(pushedBack != null) {
          line = pushedBack;
          pushedBack = null;
        } else {
          line = bufferedReader.readLine();
        }

        if (line != null) {
          SolrInputDocument lineDoc = new SolrInputDocument();
          String date = parseDate(line);
          String minute = parseMinute(line);
          String tenSecond = parseTenSecond(line);
          lineDoc.setField("date_dt", date);
          lineDoc.setField("time_minute_s", minute);
          lineDoc.setField("time_ten_second_s", tenSecond);
          lineDoc.setField("line_t", line);
          lineDoc.setField("type_s", "other"); // Overridden by known types below

          if (line.contains("Registered new searcher")) {
            parseNewSearch(lineDoc, line);
          } else if (line.contains("path=/update")) {
            parseUpdate(lineDoc, line);
          } else if (line.contains(" ERROR ")) {
            this.cause = null;
            parseError(lineDoc, line, readTrace());
          } else if (line.contains("start commit")) {
            parseCommit(lineDoc, line);
          } else if(line.contains("QTime=")) {
            parseQueryRecord(lineDoc, line);
          }

          return lineDoc;
        } else {
          return null;
        }
      }
    }

    private String readTrace() throws IOException {
      StringBuilder buf = new StringBuilder();
      buf.append("%html ");

      while(true) {
        String line = bufferedReader.readLine();
        if (line == null) {
          finished = true;
          return buf.toString();
        } else {
          //look for a date at the beginning of the line
          //If it's not there then read into the stack trace buffer
          Matcher m = p.matcher(line);

          if (!m.find() && buf.length() < 10000) {
            //Line does not start with a timestamp so append to the stack trace
            buf.append(line.replace("\t", "    ") + "
"); if(line.startsWith("Caused by:")) { this.cause = line; } } else { pushedBack = line; break; } } } return buf.toString(); } private String parseDate(String line) { Matcher m = p.matcher(line); if(m.find()) { String date = m.group(1); return date.replace(" ", "T")+"Z"; } return null; } private String parseMinute(String line) { Matcher m = minute.matcher(line); if(m.find()) { String date = m.group(1); return date.replace(" ", "T")+":00Z"; } return null; } private String parseTenSecond(String line) { Matcher m = tenSecond.matcher(line); if(m.find()) { String date = m.group(1); return date.replace(" ", "T")+"0Z"; } return null; } private void setFieldIfUnset(SolrInputDocument doc, String fieldName, String fieldValue) { if (doc.containsKey(fieldName)) return; doc.setField(fieldName, fieldValue); } private void parseError(SolrInputDocument lineRecord, String line, String trace) throws IOException { lineRecord.setField("type_s", "error"); //Don't include traces that have only the %html header. if(trace != null && trace.length() > 6) { lineRecord.setField("stack_t", trace); } if(this.cause != null) { lineRecord.setField("root_cause_t", cause.replace("Caused by:", "").trim()); } lineRecord.setField("collection_s", parseCollection(line)); lineRecord.setField("core_s", parseCore(line)); lineRecord.setField("shard_s", parseShard(line)); lineRecord.setField("replica_s", parseReplica(line)); } private void parseCommit(SolrInputDocument lineRecord, String line) throws IOException { lineRecord.setField("type_s", "commit"); lineRecord.setField("soft_commit_s", Boolean.toString(line.contains("softCommit=true"))); lineRecord.setField("open_searcher_s", Boolean.toString(line.contains("openSearcher=true"))); lineRecord.setField("collection_s", parseCollection(line)); lineRecord.setField("core_s", parseCore(line)); lineRecord.setField("shard_s", parseShard(line)); lineRecord.setField("replica_s", parseReplica(line)); } private void parseQueryRecord(SolrInputDocument lineRecord, String line) throws IOException { lineRecord.setField("date_dt", parseDate(line)); lineRecord.setField("qtime_i", parseQTime(line)); lineRecord.setField("status_s", parseStatus(line)); String path = parsePath(line); lineRecord.setField("path_s", path); if(line.contains("hits=")) { lineRecord.setField("hits_l", parseHits(line)); } String params = parseParams(line); lineRecord.setField("params_t", params); addParams(lineRecord, params); lineRecord.setField("collection_s", parseCollection(line)); lineRecord.setField("core_s", parseCore(line)); lineRecord.setField("node_s", parseNode(line)); lineRecord.setField("shard_s", parseShard(line)); lineRecord.setField("replica_s", parseReplica(line)); if(path != null && path.contains("/admin")) { lineRecord.setField("type_s", "admin"); } else if(path != null && params.contains("/replication")) { lineRecord.setField("type_s", "replication"); } else if (path != null && path.contains("/get")) { lineRecord.setField("type_s", "get"); } else { lineRecord.setField("type_s", "query"); } } private void parseNewSearch(SolrInputDocument lineRecord, String line) { lineRecord.setField("core_s", parseNewSearcherCore(line)); lineRecord.setField("type_s", "newSearcher"); } private String parseCollection(String line) { char[] ca = {' ', ']', ','}; String parts[] = line.split("c:"); if(parts.length >= 2) { return readUntil(parts[1], ca); } else { return null; } } private void parseUpdate(SolrInputDocument lineRecord, String line) { if(line.contains("deleteByQuery=")) { lineRecord.setField("type_s", "deleteByQuery"); } else if(line.contains("delete=")) { lineRecord.setField("type_s", "delete"); } else { lineRecord.setField("type_s", "update"); } lineRecord.setField("collection_s", parseCollection(line)); lineRecord.setField("core_s", parseCore(line)); lineRecord.setField("shard_s", parseShard(line)); lineRecord.setField("replica_s", parseReplica(line)); } private String parseNewSearcherCore(String line) { char[] ca = {']'}; String parts[] = line.split("\\["); if(parts.length > 3) { return readUntil(parts[2], ca); } else { return null; } } private String parseCore(String line) { char[] ca = {' ', ']', '}', ','}; String parts[] = line.split("x:"); if(parts.length >= 2) { return readUntil(parts[1], ca); } else { return null; } } private String parseShard(String line) { char[] ca = {' ', ']', '}', ','}; String parts[] = line.split("s:"); if(parts.length >= 2) { return readUntil(parts[1], ca); } else { return null; } } private String parseReplica(String line) { char[] ca = {' ', ']', '}',','}; String parts[] = line.split("r:"); if(parts.length >= 2) { return readUntil(parts[1], ca); } else { return null; } } private String parsePath(String line) { char[] ca = {' '}; String parts[] = line.split(" path="); if(parts.length == 2) { return readUntil(parts[1], ca); } else { return null; } } private String parseQTime(String line) { char[] ca = {'\n', '\r'}; String parts[] = line.split(" QTime="); if(parts.length == 2) { return readUntil(parts[1], ca); } else { return null; } } private String parseNode(String line) { char[] ca = {' ', ']', '}', ','}; String parts[] = line.split("node_name=n:"); if(parts.length >= 2) { return readUntil(parts[1], ca); } else { return null; } } private String parseStatus(String line) { char[] ca = {' ', '\n', '\r'}; String parts[] = line.split(" status="); if(parts.length == 2) { return readUntil(parts[1], ca); } else { return null; } } private String parseHits(String line) { char[] ca = {' '}; String parts[] = line.split(" hits="); if(parts.length == 2) { return readUntil(parts[1], ca); } else { return null; } } private String parseParams(String line) { char[] ca = {' '}; String parts[] = line.split(" params="); if(parts.length == 2) { String p = readUntil(parts[1].substring(1), ca); return p.substring(0, p.length()-1); } else { return null; } } private String readUntil(String s, char[] chars) { StringBuilder builder = new StringBuilder(); for(int i=0; i purposes; protected static final String UNKNOWN_VALUE = "Unknown"; private static final String[] purposeUnknown = new String[] { UNKNOWN_VALUE }; public static String[] getRequestPurposeNames(Integer reqPurpose) { if (reqPurpose != null) { int valid = 0; for (Map.Entryentry : purposes.entrySet()) { if ((reqPurpose & entry.getKey()) != 0) { valid++; } } if (valid == 0) { return purposeUnknown; } else { String[] result = new String[valid]; int i = 0; for (Map.Entryentry : purposes.entrySet()) { if ((reqPurpose & entry.getKey()) != 0) { result[i] = entry.getValue(); i++; } } return result; } } return purposeUnknown; } static { Map map = new TreeMap<>(); map.put(ShardRequest.PURPOSE_PRIVATE, "PRIVATE"); map.put(ShardRequest.PURPOSE_GET_TOP_IDS, "GET_TOP_IDS"); map.put(ShardRequest.PURPOSE_REFINE_TOP_IDS, "REFINE_TOP_IDS"); map.put(ShardRequest.PURPOSE_GET_FACETS, "GET_FACETS"); map.put(ShardRequest.PURPOSE_REFINE_FACETS, "REFINE_FACETS"); map.put(ShardRequest.PURPOSE_GET_FIELDS, "GET_FIELDS"); map.put(ShardRequest.PURPOSE_GET_HIGHLIGHTS, "GET_HIGHLIGHTS"); map.put(ShardRequest.PURPOSE_GET_DEBUG, "GET_DEBUG"); map.put(ShardRequest.PURPOSE_GET_STATS, "GET_STATS"); map.put(ShardRequest.PURPOSE_GET_TERMS, "GET_TERMS"); map.put(ShardRequest.PURPOSE_GET_TOP_GROUPS, "GET_TOP_GROUPS"); map.put(ShardRequest.PURPOSE_GET_MLT_RESULTS, "GET_MLT_RESULTS"); map.put(ShardRequest.PURPOSE_REFINE_PIVOT_FACETS, "REFINE_PIVOT_FACETS"); map.put(ShardRequest.PURPOSE_SET_TERM_STATS, "SET_TERM_STATS"); map.put(ShardRequest.PURPOSE_GET_TERM_STATS, "GET_TERM_STATS"); purposes = Collections.unmodifiableMap(map); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy