/* * 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.ignite.internal.processors.rest.handlers.log; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.file.InvalidPathException; import java.util.Collection; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.processors.rest.GridRestCommand; import org.apache.ignite.internal.processors.rest.GridRestResponse; import org.apache.ignite.internal.processors.rest.handlers.GridRestCommandHandlerAdapter; import org.apache.ignite.internal.processors.rest.request.GridRestLogRequest; import org.apache.ignite.internal.processors.rest.request.GridRestRequest; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.typedef.internal.U; import static org.apache.ignite.internal.processors.rest.GridRestCommand.LOG; /** * Handler for {@link org.apache.ignite.internal.processors.rest.GridRestCommand#LOG} command. */ public class GridLogCommandHandler extends GridRestCommandHandlerAdapter { /** * Supported commands. */ private static final Collection<GridRestCommand> SUPPORTED_COMMANDS = U.sealList(LOG); /** * Default log file start line number * */ private static final int DEFAULT_FROM = 0; /** * Default log file end line number* */ private static final int DEFAULT_TO = 1; /** * @param ctx Context. */ public GridLogCommandHandler(GridKernalContext ctx) { super(ctx); } /** {@inheritDoc} */ @Override public Collection<GridRestCommand> supportedCommands() { return SUPPORTED_COMMANDS; } /** {@inheritDoc} */ @Override public IgniteInternalFuture<GridRestResponse> handleAsync(GridRestRequest req) { assert req != null; if (req.command() == LOG) { if (log.isDebugEnabled()) log.debug("Handling log REST request: " + req); GridRestLogRequest req0 = (GridRestLogRequest)req; if (req0.from() < -1 || req0.to() < -1) return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, "One of the request parameters is invalid [from=" + req0.from() + ", to=" + req0.to() + ']')); int from; if (req0.from() != -1) { if (req0.to() == -1) return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, "Request parameter 'to' is not set.")); from = req0.from(); } else from = DEFAULT_FROM; int to; if (req0.to() != -1) { if (req0.from() == -1) return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, "Request parameter 'from' is not set.")); to = req0.to(); } else to = DEFAULT_TO; if (from >= to) return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, "Request parameter 'from' must be less than 'to'.")); File logFile; try { if (req0.path() != null) { if (log.fileName() != null) { if (!req0.path().equals(log.fileName())) { return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, "Request parameter 'path' must contain a path to valid log file.")); } else logFile = new File(req0.path()); } else if (req0.path().startsWith(ctx.config().getIgniteHome())) logFile = new File(req0.path()); else { return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, "Request parameter 'path' must contain a path to valid log file.")); } } else if (log.fileName() == null) logFile = new File(ctx.config().getIgniteHome() + "/work/log/ignite.log"); else logFile = new File(log.fileName()); } catch (InvalidPathException e) { return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, "Incorrect path to a log file [msg=" + e.getMessage() + ']')); } try { String content = readLog(from, to, logFile); return new GridFinishedFuture<>(new GridRestResponse(content)); } catch (IgniteCheckedException e) { return new GridFinishedFuture<>(new GridRestResponse(GridRestResponse.STATUS_FAILED, e.getMessage())); } } return new GridFinishedFuture<>(); } /** * Reads content from a log file. * * @param from Start position. * @param to End position. * @param logFile Log file. * @return Content that is read. * @throws IgniteCheckedException If failed. */ private String readLog(int from, int to, File logFile) throws IgniteCheckedException { StringBuilder content = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(logFile))) { String line; int start = 0; while (start <= to && (line = reader.readLine()) != null) { if (start >= from) content.append(line); start++; } if (content.length() == 0) throw new IgniteCheckedException("Request parameter 'from' and 'to' are for lines that " + "do not exist in log file."); } catch (IOException e) { throw new IgniteCheckedException(e); } return content.toString(); } }