blob: 48fe2226e1edf67bbaecd5d0043b8386d74a6158 [file] [log] [blame]
/**
* 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.ui.controller;
import com.alibaba.jstorm.client.ConfigExtension;
import com.alibaba.jstorm.cluster.Common;
import com.alibaba.jstorm.ui.model.Response;
import com.alibaba.jstorm.ui.utils.UIUtils;
import com.alibaba.jstorm.utils.JStormUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Jark (wuchong.wc@alibaba-inc.com)
*/
@Controller
public class LogController {
private static final Logger LOG = LoggerFactory.getLogger(LogController.class);
@RequestMapping(value = "/log", method = RequestMethod.GET)
public String show(@RequestParam(value = "cluster", required = true) String clusterName,
@RequestParam(value = "host", required = true) String host,
@RequestParam(value = "port", required = false) String logServerPort,
@RequestParam(value = "dir", required = false) String dir,
@RequestParam(value = "wport", required = false) String workerPort,
@RequestParam(value = "file", required = false) String logName,
@RequestParam(value = "tid", required = false) String topologyId,
@RequestParam(value = "pos", required = false) String pos,
ModelMap model) {
if (StringUtils.isBlank(dir)) {
dir = ".";
}
Map conf = UIUtils.getNimbusConf(clusterName);
Event event = new Event(clusterName, host, logServerPort, logName, topologyId, workerPort, pos, dir, conf);
try {
requestLog(event, model);
} catch (IOException e) {
e.printStackTrace();
}
model.addAttribute("logName", event.logName);
model.addAttribute("host", host);
model.addAttribute("dir", event.dir);
model.addAttribute("clusterName", clusterName);
return "log";
}
private long getCurrentPageIndex(Event e, long totalSize, int pageSize) {
long currentPos = totalSize;
if (e.pos >= 0) {
currentPos = e.pos;
}
return currentPos / pageSize;
}
private Pagination createPage(Event e, long index, int pageSize, String text,
boolean isDisable, boolean isActive) {
long pos = index * pageSize;
String url = String.format("log?cluster=%s&host=%s&port=%s&file=%s&pos=%s&dir=%s",
e.clusterName, e.host, e.logServerPort, e.logName, pos, e.dir);
Pagination page = new Pagination();
page.url = url;
page.text = text;
if (isDisable) {
page.status = "disabled";
} else if (isActive) {
page.status = "active";
}
return page;
}
private List<Pagination> genPageUrl(Event e, String sizeStr) {
long totalSize = Long.valueOf(sizeStr);
int pageSize = e.logPageSize;
long pageNum = (totalSize + pageSize - 1) / pageSize;
long currentPageIndex = getCurrentPageIndex(e, totalSize, pageSize);
List<Pagination> pages = new ArrayList<>();
if (pageNum <= 10) {
for (long i = pageNum - 1; i >= 0; i--) {
pages.add(createPage(e, i, pageSize, String.valueOf(i + 1), false, i == currentPageIndex));
}
return pages;
}
if (pageNum - currentPageIndex < 5) {
for (long i = pageNum - 1; i >= currentPageIndex; i--) {
pages.add(createPage(e, i, pageSize, String.valueOf(i + 1), false, i == currentPageIndex));
}
} else {
pages.add(createPage(e, pageNum - 1, pageSize, "End", false, pageNum - 1 == currentPageIndex));
pages.add(createPage(e, currentPageIndex + 4, pageSize, "...", false, false));
for (long i = currentPageIndex + 3; i >= currentPageIndex; i--) {
pages.add(createPage(e, i, pageSize, String.valueOf(i + 1), false, i == currentPageIndex));
}
}
if (currentPageIndex < 5) {
for (long i = currentPageIndex - 1; i > 0; i--) {
pages.add(createPage(e, i, pageSize, String.valueOf(i + 1), false, i == currentPageIndex));
}
} else {
for (long i = currentPageIndex - 1; i >= currentPageIndex - 3; i--) {
pages.add(createPage(e, i, pageSize, String.valueOf(i + 1), false, i == currentPageIndex));
}
pages.add(createPage(e, currentPageIndex - 4, pageSize, "...", false, false));
pages.add(createPage(e, 0, pageSize, "Begin", false, 0 == currentPageIndex));
}
return pages;
}
private void requestLog(Event e, ModelMap model) throws IOException {
String fullPath;
if (e.dir == null || e.dir.equals(".")) {
fullPath = e.logName;
} else {
fullPath = e.dir + File.separator + e.logName;
}
String summary = null;
String log = null;
if (fullPath.contains("/..") || fullPath.contains("../")){
summary = "File Path can't contains <code>..</code> <br/>";
}else {
Response res = UIUtils.getLog(e.host, e.logServerPort, fullPath, e.pos);
if (res.getStatus() != -1) {
if (res.getStatus() == 200) {
String sizeStr = res.getData().substring(0, 16);
model.addAttribute("pages", genPageUrl(e, sizeStr));
log = res.getData().substring(17);
} else {
summary = "The log file <code>" + e.logName + "</code> isn't exist <br/> " + res.getData();
}
} else {
summary = "Failed to get log file <code>" + e.logName + "</code> <br/>" + res.getData();
}
}
model.addAttribute("log", log);
model.addAttribute("summary", summary);
UIUtils.addTitleAttribute(model, "Log");
}
public class Event {
public String clusterName;
public String host;
public int logServerPort;
public String logName;
public String topologyId;
public String workerPort;
public long pos;
public String dir;
public int logPageSize;
public String logEncoding;
public Event(String _clusterName, String _host, String _logServerPort, String _logName,
String _topologyId, String _workerPort, String _pos, String _dir, Map conf) {
this.clusterName = _clusterName;
this.host = _host;
this.logServerPort = JStormUtils.parseInt(_logServerPort, 0);
this.logName = _logName;
this.topologyId = _topologyId;
this.workerPort = _workerPort;
this.pos = JStormUtils.parseLong(_pos, -1);
this.dir = _dir;
logPageSize = ConfigExtension.getLogPageSize(conf);
logEncoding = ConfigExtension.getLogViewEncoding(conf);
if (host == null) {
throw new IllegalArgumentException("Please set host");
} else if (logServerPort == 0) {
throw new IllegalArgumentException(
"Please set log server's port");
}
if (!StringUtils.isBlank(logName)) {
return;
}
if (topologyId == null || workerPort == null) {
throw new IllegalArgumentException(
"Please set log fileName or topologyId-workerPort");
}
String topologyName;
try {
topologyName = Common.topologyIdToName(topologyId);
} catch (Exception e) {
throw new IllegalArgumentException(
"Please set log fileName or topologyId-workerPort");
}
dir = "." + File.separator + topologyName;
logName = topologyName + "-worker-" + workerPort + ".log";
}
}
public class Pagination {
public String status;
public String url;
public String text;
public Pagination(String status, String url, String text) {
this.status = status;
this.url = url;
this.text = text;
}
public Pagination() {
}
public String getStatus() {
return status;
}
public String getUrl() {
return url;
}
public String getText() {
return text;
}
}
}