/**
* 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 com.alibaba.jstorm.daemon.supervisor;
import backtype.storm.Constants;
import backtype.storm.daemon.Shutdownable;
import backtype.storm.utils.Utils;
import com.alibaba.jstorm.client.ConfigExtension;
import com.alibaba.jstorm.daemon.worker.Worker;
import com.alibaba.jstorm.utils.*;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* @author Johnfang (xiaojian.fxj@alibaba-inc.com)
*/
public class Httpserver implements Shutdownable {
private static Logger LOG = LoggerFactory.getLogger(Httpserver.class);
private HttpServer hs;
private int port;
private Map conf;
public Httpserver(int port, Map conf) {
this.port = port;
this.conf = conf;
}
static class LogHandler implements HttpHandler {
private String logDir;
private String stormHome;
private ArrayList<String> accessDirs = new ArrayList<String>();
Map conf;
private final int pageSize;
private boolean debug = false;
public LogHandler(Map conf) {
this.pageSize = ConfigExtension.getLogPageSize(conf);
logDir = JStormUtils.getLogDir();
String logDirPath = PathUtils.getCanonicalPath(logDir);
if (logDirPath == null) {
accessDirs.add(logDir);
} else {
accessDirs.add(logDirPath);
}
stormHome = System.getProperty("jstorm.home");
if (stormHome != null) {
String stormHomePath = PathUtils.getCanonicalPath(stormHome);
if (stormHomePath == null) {
accessDirs.add(stormHome);
} else {
accessDirs.add(stormHomePath);
}
}
String confDir = System.getProperty(Constants.JSTORM_CONF_DIR);
if (!StringUtils.isBlank(confDir)) {
String confDirPath = PathUtils.getCanonicalPath(confDir);
if (confDirPath != null) {
accessDirs.add(confDirPath);
}
}
this.conf = conf;
LOG.info("logview logDir=" + logDir); // +++
}
@VisibleForTesting
public void setDebug(boolean debug) {
this.debug = debug;
}
@VisibleForTesting
public void setLogDir(String dir) {
this.logDir = dir;
}
public void handlFailure(HttpExchange t, String errorMsg) throws IOException {
LOG.error(errorMsg);
byte[] data = errorMsg.getBytes();
sendResponse(t, HttpURLConnection.HTTP_BAD_REQUEST, data);
}
public void handle(HttpExchange t) throws IOException {
URI uri = t.getRequestURI();
Map<String, String> paramMap = parseRawQuery(uri.getRawQuery());
LOG.info("Receive command " + paramMap);
String cmd = paramMap.get(HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD);
if (StringUtils.isBlank(cmd)) {
handlFailure(t, "Bad Request, Not set command type");
return;
}
if (HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD_SHOW.equals(cmd)) {
handleShowLog(t, paramMap);
} else if (HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD_LIST.equals(cmd)) {
handleListDir(t, paramMap);
} else if (HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD_JSTACK.equals(cmd)) {
handleJstack(t, paramMap);
} else if (HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD_JSTAT.equals(cmd)) {
handleJstat(t, paramMap);
} else if (HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD_SHOW_CONF.equals(cmd)) {
handleShowConf(t, paramMap);
} else if (HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD_SEARCH_LOG.equals(cmd)) {
handleSearchLog(t, paramMap);
} else if (HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_CMD_DOWNLOAD.equals(cmd)){
handleDownloadLog(t, paramMap);
} else {
handlFailure(t, "Bad Request, Not support command type " + cmd);
}
}
private void accessCheck(String fileName) throws IOException {
if (debug) {
return;
}
File file = new File(fileName);
String canonicalPath = file.getCanonicalPath();
boolean isChild = false;
for (String dir : accessDirs) {
if (canonicalPath.contains(dir)) {
isChild = true;
break;
}
}
if (!isChild) {
LOG.error("Access one disallowed path: " + canonicalPath);
throw new IOException("Destination file/path is not accessible.");
}
}
private Map<String, String> parseRawQuery(String uriRawQuery) {
Map<String, String> paramMap = Maps.newHashMap();
for (String param : StringUtils.split(uriRawQuery, "&")) {
String[] pair = StringUtils.split(param, "=");
if (pair.length == 2) {
paramMap.put(pair[0], pair[1]);
}
}
return paramMap;
}
private void handleShowLog(HttpExchange t, Map<String, String> paramMap) throws IOException {
Pair<Long, byte[]> logPair = queryLog(t, paramMap);
if (logPair == null) {
return;
}
String size = String.format(HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_SIZE_FORMAT, logPair.getFirst());
byte[] sizeByts = size.getBytes();
byte[] logData = logPair.getSecond();
t.sendResponseHeaders(HttpURLConnection.HTTP_OK, sizeByts.length + logData.length);
OutputStream os = t.getResponseBody();
os.write(sizeByts);
os.write(logData);
os.close();
}
private void handleDownloadLog(HttpExchange t, Map<String, String> paramMap) throws IOException {
Pair<Long, byte[]> logPair = queryLog(t, paramMap);
sendResponse(t, HttpURLConnection.HTTP_OK, logPair.getSecond());
}
private Pair<Long, byte[]> queryLog(HttpExchange t, Map<String, String> paramMap) throws IOException {
String fileParam = paramMap.get(HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_LOGFILE);
String _pageSize = paramMap.get(HttpserverUtils.HTTPSERVER_LOGVIEW_PAGE_SIZE);
if (StringUtils.isBlank(fileParam)) {
handlFailure(t, "Bad Request, Params Error, no log file name.");
return null;
}
int pageSize = this.pageSize;
if (!StringUtils.isBlank(_pageSize)) {
pageSize = JStormUtils.parseInt(_pageSize, this.pageSize);
}
String logFile = Joiner.on(File.separator).join(logDir, fileParam);
accessCheck(logFile);
FileChannel fc = null;
MappedByteBuffer fout;
long fileSize;
byte[] ret;
try {
fc = new RandomAccessFile(logFile, "r").getChannel();
fileSize = fc.size();
long position = fileSize - pageSize;
try {
String posStr = paramMap.get(HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_POS);
if (!StringUtils.isBlank(posStr)) {
position = Long.valueOf(posStr);
}
} catch (Exception e) {
LOG.warn("Invalide position " + position);
}
if (position < 0) {
position = 0L;
}
long size = Math.min(fileSize - position, pageSize);
LOG.info("logview " + logFile + ", position=" + position + ", size=" + size);
fout = fc.map(FileChannel.MapMode.READ_ONLY, position, size);
ret = new byte[(int) size];
fout.get(ret);
String str = new String(ret, ConfigExtension.getLogViewEncoding(conf));
return new Pair<>(fileSize, str.getBytes());
} catch (FileNotFoundException e) {
LOG.warn(e.getMessage(), e);
handlFailure(t, "Bad Request, Failed to find " + fileParam);
return null;
} catch (IOException e) {
LOG.warn(e.getMessage(), e);
handlFailure(t, "Bad Request, Failed to open " + fileParam);
return null;
} finally {
if (fc != null) {
IOUtils.closeQuietly(fc);
}
}
}
byte[] getJSonFiles(String dir) throws Exception {
Map<String, FileAttribute> fileMap = new HashMap<String, FileAttribute>();
String path = logDir;
if (dir != null) {
path = path + File.separator + dir;
}
accessCheck(path);
LOG.info("List dir " + path);
File file = new File(path);
String[] files = file.list();
if (files == null) {
files = new String[] {};
}
for (String fileName : files) {
String logFile = Joiner.on(File.separator).join(path, fileName);
FileAttribute fileAttribute = new FileAttribute();
fileAttribute.setFileName(fileName);
File subFile = new File(logFile);
Date modify = new Date(subFile.lastModified());
fileAttribute.setModifyTime(TimeFormat.getSecond(modify));
if (subFile.isFile()) {
fileAttribute.setIsDir(String.valueOf(false));
fileAttribute.setSize(String.valueOf(subFile.length()));
fileMap.put(logFile, fileAttribute);
} else if (subFile.isDirectory()) {
fileAttribute.setIsDir(String.valueOf(true));
fileAttribute.setSize(String.valueOf(4096));
fileMap.put(logFile, fileAttribute);
}
}
String fileJsonStr = JStormUtils.to_json(fileMap);
return fileJsonStr.getBytes();
}
void handleListDir(HttpExchange t, Map<String, String> paramMap) throws IOException {
byte[] filesJson;
try {
String dir = paramMap.get(HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_DIR);
filesJson = getJSonFiles(dir);
} catch (Exception e) {
LOG.error("Failed to list files", e);
handlFailure(t, "Failed to get file list");
return;
}
sendResponse(t, HttpURLConnection.HTTP_OK, filesJson);
}
/**
* log search, migrated from STORM-902
*
* the following params are needed:
* - file *
* - offset *
* - max_match
* - look_back: num of context lines backward from match
* - look_ahead: num of context lines forward from match
* - key:* search keyword
* - case_ignore: true/false
* - search_from: search direction, head: from begin to end, tail: from end to begin, default is tail
*
* following values are returned:
* - error: true/false
* - msg: the error msg if any
* - num_match: the match num
* - next_offset
* - match_results: map<offset, match_result> note that no consecutive match results are overlapped.
*/
void handleSearchLog(HttpExchange t, Map<String, String> paramMap) throws IOException {
int maxMatch = JStormUtils.parseInt(paramMap.get("max_match"), ConfigExtension.getMaxMatchPerLogSearch(conf));
long offset = JStormUtils.parseLong(paramMap.get("offset"), 0);
String logFile = paramMap.get("file");
int lookBack = JStormUtils.parseInt(paramMap.get("look_back"), 2);
int lookAhead = JStormUtils.parseInt(paramMap.get("look_ahead"), 10);
boolean caseIgnore = JStormUtils.parseBoolean(paramMap.get("case_ignore"), false);
int maxBlocks = ConfigExtension.getMaxBlocksPerLogSearch(conf);
int blockSize = HttpserverUtils.LOG_SEARCH_BLOCK_SIZE;
String key = paramMap.get("key");
if (caseIgnore){
key = key.toLowerCase();
}
key = URLDecoder.decode(key, "UTF-8");
Map<Object, Object> ret = new HashMap<>();
if (StringUtils.isBlank(key)) {
error(ret, "search key cannot be empty!");
String resp = JStormUtils.to_json(ret);
sendResponse(t, HttpURLConnection.HTTP_OK, resp);
return;
}
if (debug) {
System.out.println("Search for key:" + key);
System.out.println("===================================\n");
}
logFile = Joiner.on(File.separator).join(logDir, logFile);
accessCheck(logFile);
//search
String searchFrom = paramMap.get("search_from");
if (searchFrom != null && searchFrom.equals("head")){
ret = searchFromHead(logFile, offset, key, maxMatch, lookBack, lookAhead, maxBlocks, blockSize, caseIgnore);
} else {
ret = searchFromTail(logFile, offset, key, maxMatch, lookBack, lookAhead, maxBlocks, blockSize, caseIgnore);
}
String resp = JStormUtils.to_json(ret);
sendResponse(t, HttpURLConnection.HTTP_OK, resp);
}
private Map<Object, Object> searchFromTail(String logFile, long offset, String key, int maxMatch, int lookBack,
int lookAhead, int maxBlocks, int blockSize, boolean caseIgnore) throws IOException {
Map<Object, Object> ret = new HashMap<>();
Map<Long, String> matchResults = new HashMap<>(); //<offset, match content>
int match = 0;
String encoding = ConfigExtension.getLogViewEncoding(conf);
FileChannel fc = null;
MappedByteBuffer fout;
final long fileSize;
try {
RandomAccessFile randomAccess = new RandomAccessFile(logFile, "r");
fc = randomAccess.getChannel();
fileSize = fc.size();
if (offset == 0 || offset < fileSize) {
// if offset is 0, we search from the end.
long pos = fileSize;
// user have not specify search start position, we start from end default
if (offset > 0) {
pos = offset;
}
long matchOffset = pos; // the offset of match result
int jumpLines = 0;
StringBuilder matchContent = new StringBuilder();
for (int i = 0; i < maxBlocks && pos > 0 && match < maxMatch; i++) {
long bufferSize = blockSize;
if (pos < blockSize) {
// if current pos is less than block size , we start search from begin
bufferSize = pos;
pos = 0;
} else {
pos = pos - bufferSize;
}
fout = fc.map(FileChannel.MapMode.READ_ONLY, pos, bufferSize);
byte[] buffer = new byte[(int) bufferSize];
fout.get(buffer);
String data = new String(buffer, encoding);
String[] lines = data.split("\\r\\n|\\n|\\r");
int[] line2pos = new int[lines.length]; //the position of the end of the line
for (int j = 0; j < lines.length; j++) {
line2pos[j] = lines[j].getBytes(encoding).length;
if (j > 0) {
line2pos[j] += line2pos[j - 1];
}
}
// begin to search this block
for (int j = 0; j < lines.length; ) {
String line = lines[j];
boolean isMatch = caseIgnore ? line.toLowerCase().contains(key) : line.contains(key);
if (isMatch) {
int start = Math.max(0, j - lookBack);
j += lookAhead;
matchOffset = start > 0 ? pos + line2pos[start-1] : pos;
// jumps out of current block
if (j >= lines.length) {
jumpLines = j - lines.length + 1;
j = lines.length - 1;
}
match++;
// make partial search result, if there's jumpLines, the result is not complete.
// will not append the last line
for (int k = start; k < j; k++) {
matchContent.append(lines[k]).append("\n");
}
// concat the jump out lines
if (jumpLines > 0) {
readJumpLines(randomAccess, pos + line2pos[j], jumpLines, matchContent);
jumpLines = 0;
j = lines.length;
}
// if it's the last match, we should ignore jumpLines
matchResults.put(matchOffset, matchContent.toString());
if (debug) {
System.out.println("==== match " + match + " ==== offset: " + matchOffset);
System.out.println(matchContent.toString());
System.out.println();
}
matchContent = new StringBuilder();
} else {
j++;
}
}
if (match < maxMatch && pos > 0) {
// move back from the line/word break
int lineBreakOffset = lines[0].getBytes(encoding).length;
if (lineBreakOffset < blockSize) {
pos = pos + lineBreakOffset;
}
}
}
ret.put("num_match", match);
ret.put("match_results", matchResults);
ret.put("next_offset", pos);
} else {
error(ret, "pos exceeds file size!");
}
} catch (FileNotFoundException e) {
LOG.warn("Error", e);
error(ret, "Bad Request, Failed to find " + logFile);
} catch (IOException e) {
LOG.warn("Error", e);
error(ret, "Bad Request, Failed to open " + logFile);
} finally {
if (fc != null) {
IOUtils.closeQuietly(fc);
}
}
return ret;
}
private void readJumpLines(RandomAccessFile randomAccessFile, long pos, int lines, StringBuilder matchContent){
try {
randomAccessFile.seek(pos);
while(lines-- > 0){
String line = randomAccessFile.readLine();
if (line != null){
matchContent.append(line).append("\n");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private Map<Object, Object> searchFromHead(String logFile, long offset, String key, int maxMatch, int lookBack,
int lookAhead, int maxBlocks, int blockSize, boolean caseIgnore) throws IOException {
Map<Object, Object> ret = new HashMap<>();
Map<Long, String> matchResults = new HashMap<>(); //<offset, match content>
int match = 0;
String encoding = ConfigExtension.getLogViewEncoding(conf);
FileChannel fc = null;
MappedByteBuffer fout;
long fileSize;
try {
fc = new RandomAccessFile(logFile, "r").getChannel();
fileSize = fc.size();
if (offset < fileSize) {
long pos = offset;
long matchOffset = offset;
int jumpLines = 0;
StringBuilder matchContent = new StringBuilder();
for (int i = 0; i < maxBlocks && pos < fileSize && match < maxMatch; i++) {
long bufferSize = Math.min(fc.size() - pos, blockSize);
fout = fc.map(FileChannel.MapMode.READ_ONLY, pos, bufferSize);
byte[] buffer = new byte[(int) bufferSize];
fout.get(buffer);
String data = new String(buffer, encoding);
String[] lines = data.split("\\r\\n|\\n|\\r");
int[] line2pos = new int[lines.length];
for (int j = 0; j < lines.length; j++) {
line2pos[j] = lines[j].getBytes(encoding).length;
if (j > 0) {
line2pos[j] += line2pos[j - 1];
}
}
for (int j = 0; j < lines.length && match < maxMatch; ) {
// rotate lines from last match
if (jumpLines > 0) {
for (int m = 0; m < jumpLines && m < lines.length; m++) {
matchContent.append(lines[m]).append("\n");
}
j = jumpLines;
jumpLines = 0;
// matchResults.add(matchContent.toString());
matchResults.put(matchOffset, matchContent.toString());
if (debug) {
// System.out.println("==== match " + match + " ====");
System.out.println("==== match " + match + " ==== offset: " + matchOffset);
System.out.println(matchContent.toString());
System.out.println();
}
matchContent = new StringBuilder();
continue;
}
String line = lines[j];
boolean isMatch = caseIgnore ? line.toLowerCase().contains(key) : line.contains(key);
if (isMatch) {
int start = Math.max(0, j - lookBack);
j += lookAhead;
matchOffset = start > 0 ? pos + line2pos[start-1] : pos;
// jumps out of current block
if (j >= lines.length) {
jumpLines = j - lines.length + 1;
j = lines.length -1 ;
}
// search finishes
if (++match >= maxMatch) {
pos += line2pos[j];
}
// make partial search result, if there's jumpLines, the result is not complete.
for (int k = start; k < j; k++) {
matchContent.append(lines[k]).append("\n");
}
// if it's the last match, we should ignore jumpLines
if (jumpLines == 0 || match >= maxMatch) {
// matchResults.add(matchContent.toString());
matchResults.put(matchOffset, matchContent.toString());
if (debug) {
System.out.println("==== match " + match + " ==== offset: " + matchOffset);
System.out.println(matchContent.toString());
System.out.println();
}
matchContent = new StringBuilder();
} else {
j++;
}
} else {
j++;
}
}
if (match < maxMatch) {
// move back from the line/word break
int lineBreakOffset = lines[lines.length - 1].getBytes(encoding).length;
if (lineBreakOffset < blockSize) {
pos = pos + blockSize - lineBreakOffset;
} else {
pos += blockSize;
}
}
}
ret.put("num_match", match);
ret.put("match_results", matchResults);
ret.put("next_offset", pos);
} else {
error(ret, "pos exceeds file size!");
}
} catch (FileNotFoundException e) {
LOG.warn("Error", e);
error(ret, "Bad Request, Failed to find " + logFile);
} catch (IOException e) {
LOG.warn("Error", e);
error(ret, "Bad Request, Failed to open " + logFile);
} finally {
if (fc != null) {
IOUtils.closeQuietly(fc);
}
}
return ret;
}
void error(Map<Object, Object> ret, String msg) {
ret.put("error", true);
ret.put("msg", msg);
}
void handleJstack(StringBuilder sb, Integer pid) {
String cmd = "jstack " + pid;
try {
LOG.info("Begin to execute " + cmd);
String output = JStormUtils.launchProcess(cmd, new HashMap<String, String>(), false);
sb.append(output);
LOG.info("Successfully get output of " + cmd);
} catch (IOException e) {
LOG.info("Failed to execute " + cmd, e);
sb.append("Failed to execute " + cmd);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
sb.append("Failed to execute " + cmd + ", " + e.getCause());
}
}
void handleJstat (StringBuilder sb, Integer pid) {
String cmd = "jstat -gc " + pid;
try {
LOG.info("Begin to execute " + cmd);
String output = JStormUtils.launchProcess(cmd, new HashMap<String, String>(), false);
sb.append(output);
LOG.info("Successfully get output of " + cmd);
} catch (IOException e) {
LOG.info("Failed to execute " + cmd, e);
sb.append("Failed to execute " + cmd);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
sb.append("Failed to execute " + cmd + ", " + e.getCause());
}
}
void handleJstack(HttpExchange t, Map<String, String> paramMap) throws IOException {
String workerPort = paramMap.get(HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_WORKER_PORT);
if (workerPort == null) {
handlFailure(t, "Not set worker's port");
return;
}
LOG.info("Begin to get jstack of " + workerPort);
StringBuilder sb = new StringBuilder();
List<Integer> pids = Worker.getOldPortPids(workerPort);
for (Integer pid : pids) {
sb.append("!!!!!!!!!!!!!!!!!!\r\n");
sb.append("WorkerPort:" + workerPort + ", pid:" + pid);
sb.append("\r\n!!!!!!!!!!!!!!!!!!\r\n");
handleJstack(sb, pid);
}
byte[] data = sb.toString().getBytes();
sendResponse(t, HttpURLConnection.HTTP_OK, data);
}
void handleJstat(HttpExchange t, Map<String, String> paramMap) throws IOException {
String workerPort = paramMap.get(HttpserverUtils.HTTPSERVER_LOGVIEW_PARAM_WORKER_PORT);
if (workerPort == null) {
handlFailure(t, "Not set worker's port");
return;
}
LOG.info("Begin to get jstat of " + workerPort);
StringBuilder sb = new StringBuilder();
List<Integer> pids = Worker.getOldPortPids(workerPort);
for (Integer pid : pids) {
sb.append("!!!!!!!!!!!!!!!!!!\r\n");
sb.append("WorkerPort:" + workerPort + ", pid:" + pid);
sb.append("\r\n!!!!!!!!!!!!!!!!!!\r\n");
handleJstat(sb, pid);
}
byte[] data = sb.toString().getBytes();
sendResponse(t, HttpURLConnection.HTTP_OK, data);
}
void handleShowConf(HttpExchange t, Map<String, String> paramMap) throws IOException {
byte[] json;
try {
String tmp = Utils.to_json(conf);
json = tmp.getBytes();
} catch (Exception e) {
LOG.error("Failed to get configuration", e);
handlFailure(t, "Failed to get configuration");
return;
}
sendResponse(t, HttpURLConnection.HTTP_OK, json);
}
void sendResponse(HttpExchange t, int retCode, String data) throws IOException {
if (debug) {
LOG.info("HTTP:{}, search result:{}", retCode, data);
}
byte[] bytes = data.getBytes();
sendResponse(t, retCode, bytes);
}
void sendResponse(HttpExchange t, int retCode, byte[] data) throws IOException {
if (t != null) {
t.sendResponseHeaders(retCode, data.length);
OutputStream os = t.getResponseBody();
os.write(data);
os.close();
}
}
}// LogHandler
public void start() {
int numHandler = 3;
InetSocketAddress socketAddr = new InetSocketAddress(port);
Executor executor = Executors.newFixedThreadPool(numHandler);
try {
hs = HttpServer.create(socketAddr, 0);
hs.createContext(HttpserverUtils.HTTPSERVER_CONTEXT_PATH_LOGVIEW, new LogHandler(conf));
hs.setExecutor(executor);
hs.start();
} catch (BindException e) {
LOG.info("HttpServer Already start!");
hs = null;
return;
} catch (IOException e) {
LOG.error("HttpServer Start Failed", e);
hs = null;
return;
}
LOG.info("Success start HttpServer at port:" + port);
}
@Override
public void shutdown() {
if (hs != null) {
hs.stop(0);
LOG.info("Successfully stop http server");
}
}
public static void main(String[] args) throws Exception {
Map conf = new HashMap();
LogHandler logHandler = new LogHandler(conf);
logHandler.setDebug(true);
logHandler.setLogDir("/Users/wuchong/Downloads/");
Map<String, String> params = new HashMap<>();
// params.put("offset", "0");
// params.put("search_from", "head");
params.put("file", "SequenceTest6-worker-6800.log");
logHandler.handleSearchLog(null, params);
params.put("key", "info");
logHandler.handleSearchLog(null, params);
params.put("case_ignore", "true");
logHandler.handleSearchLog(null, params);
params.put("offset", "7481");
logHandler.handleSearchLog(null, params);
}
}