You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kh...@apache.org on 2017/03/17 20:11:23 UTC

[48/49] geode git commit: refactor for testability

refactor for testability

Extract inner Interceptor class from ExportLogsCommand


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/2bcba1da
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/2bcba1da
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/2bcba1da

Branch: refs/heads/feature/GEODE-2420
Commit: 2bcba1daae43247ee6dde673c36adba4f7142932
Parents: 26700b5
Author: Ken Howe <kh...@pivotal.io>
Authored: Fri Mar 17 12:59:59 2017 -0700
Committer: Ken Howe <kh...@pivotal.io>
Committed: Fri Mar 17 13:09:46 2017 -0700

----------------------------------------------------------------------
 .../internal/cli/commands/ExportLogCommand.java | 251 -------------------
 .../cli/commands/ExportLogsCommand.java         | 192 ++++++++++++++
 .../cli/commands/ExportLogsInterceptor.java     | 108 ++++++++
 .../cli/functions/ExportLogsFunction.java       |   6 +-
 .../cli/commands/ExportLogsCommandTest.java     |  47 ++++
 .../cli/commands/ExportLogsDUnitTest.java       |   4 +-
 .../ExportLogsInterceptorJUnitTest.java         |   4 +-
 .../cli/commands/ExportLogsStatsDUnitTest.java  |   2 +-
 8 files changed, 355 insertions(+), 259 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogCommand.java
deleted file mode 100644
index 7dfc63d..0000000
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogCommand.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * 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.geode.management.internal.cli.commands;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.geode.cache.Region;
-import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.internal.cache.GemFireCacheImpl;
-import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.management.cli.CliMetaData;
-import org.apache.geode.management.cli.ConverterHint;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor;
-import org.apache.geode.management.internal.cli.CliUtil;
-import org.apache.geode.management.internal.cli.GfshParseResult;
-import org.apache.geode.management.internal.cli.functions.ExportLogsFunction;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.result.ResultBuilder;
-import org.apache.geode.management.internal.cli.shell.Gfsh;
-import org.apache.geode.management.internal.cli.util.ExportLogsCacheWriter;
-import org.apache.geode.management.internal.configuration.utils.ZipUtils;
-import org.apache.geode.management.internal.security.ResourceOperation;
-import org.apache.geode.security.ResourcePermission;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
-import org.springframework.shell.core.CommandMarker;
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.shell.core.annotation.CliOption;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.LocalDateTime;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class ExportLogCommand implements CommandMarker {
-  private static final Logger logger = LogService.getLogger();
-  public static final String FORMAT = "yyyy/MM/dd/HH/mm/ss/SSS/z";
-  public static final String ONLY_DATE_FORMAT = "yyyy/MM/dd";
-
-  @CliCommand(value = CliStrings.EXPORT_LOGS, help = CliStrings.EXPORT_LOGS__HELP)
-  @CliMetaData(shellOnly = false, isFileDownloadOverHttp = true,
-      interceptor = "org.apache.geode.management.internal.cli.commands.ExportLogCommand$ExportLogsInterceptor",
-      relatedTopic = {CliStrings.TOPIC_GEODE_SERVER, CliStrings.TOPIC_GEODE_DEBUG_UTIL})
-  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
-      operation = ResourcePermission.Operation.READ)
-  public Result exportLogs(
-      @CliOption(key = CliStrings.EXPORT_LOGS__DIR, help = CliStrings.EXPORT_LOGS__DIR__HELP,
-          mandatory = false) String dirName,
-      @CliOption(key = CliStrings.EXPORT_LOGS__GROUP,
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
-          optionContext = ConverterHint.MEMBERGROUP,
-          help = CliStrings.EXPORT_LOGS__GROUP__HELP) String[] groups,
-      @CliOption(key = CliStrings.EXPORT_LOGS__MEMBER,
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
-          optionContext = ConverterHint.ALL_MEMBER_IDNAME,
-          help = CliStrings.EXPORT_LOGS__MEMBER__HELP) String[] memberIds,
-      @CliOption(key = CliStrings.EXPORT_LOGS__LOGLEVEL,
-          unspecifiedDefaultValue = LogService.DEFAULT_LOG_LEVEL,
-          optionContext = ConverterHint.LOG_LEVEL,
-          help = CliStrings.EXPORT_LOGS__LOGLEVEL__HELP) String logLevel,
-      @CliOption(key = CliStrings.EXPORT_LOGS__UPTO_LOGLEVEL, unspecifiedDefaultValue = "false",
-          help = CliStrings.EXPORT_LOGS__UPTO_LOGLEVEL__HELP) boolean onlyLogLevel,
-      @CliOption(key = CliStrings.EXPORT_LOGS__MERGELOG, unspecifiedDefaultValue = "false",
-          help = CliStrings.EXPORT_LOGS__MERGELOG__HELP) boolean mergeLog,
-      @CliOption(key = CliStrings.EXPORT_LOGS__STARTTIME,
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
-          help = CliStrings.EXPORT_LOGS__STARTTIME__HELP) String start,
-      @CliOption(key = CliStrings.EXPORT_LOGS__ENDTIME,
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
-          help = CliStrings.EXPORT_LOGS__ENDTIME__HELP) String end,
-      @CliOption(key = CliStrings.EXPORT_LOGS__LOGSONLY, unspecifiedDefaultValue = "false",
-          specifiedDefaultValue = "true",
-          help = CliStrings.EXPORT_LOGS__LOGSONLY__HELP) boolean logsOnly,
-      @CliOption(key = CliStrings.EXPORT_LOGS__STATSONLY, unspecifiedDefaultValue = "false",
-          specifiedDefaultValue = "true",
-          help = CliStrings.EXPORT_LOGS__STATSONLY__HELP) boolean statsOnly) {
-    Result result = null;
-    GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
-    try {
-      Set<DistributedMember> targetMembers =
-          CliUtil.findMembersIncludingLocators(groups, memberIds);
-
-      if (targetMembers.isEmpty()) {
-        return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
-      }
-
-      Map<String, Path> zipFilesFromMembers = new HashMap<>();
-      for (DistributedMember server : targetMembers) {
-        Region region = ExportLogsFunction.createOrGetExistingExportLogsRegion(true, cache);
-
-        ExportLogsCacheWriter cacheWriter =
-            (ExportLogsCacheWriter) region.getAttributes().getCacheWriter();
-
-        cacheWriter.startFile(server.getName());
-
-        CliUtil.executeFunction(new ExportLogsFunction(),
-            new ExportLogsFunction.Args(start, end, logLevel, onlyLogLevel, logsOnly, statsOnly),
-            server).getResult();
-        Path zipFile = cacheWriter.endFile();
-        ExportLogsFunction.destroyExportLogsRegion(cache);
-
-        // only put the zipfile in the map if it is not null
-        if (zipFile != null) {
-          logger.info("Received zip file from member {}: {}", server.getId(), zipFile);
-          zipFilesFromMembers.put(server.getId(), zipFile);
-        }
-      }
-
-      if (zipFilesFromMembers.isEmpty()) {
-        return ResultBuilder.createUserErrorResult("No files to be exported.");
-      }
-
-      Path tempDir = Files.createTempDirectory("exportedLogs");
-      // make sure the directory is created, so that even if there is no files unzipped to this dir,
-      // we can
-      // still zip it and send an empty zip file back to the client
-      Path exportedLogsDir = tempDir.resolve("exportedLogs");
-      FileUtils.forceMkdir(exportedLogsDir.toFile());
-
-      for (Path zipFile : zipFilesFromMembers.values()) {
-        Path unzippedMemberDir =
-            exportedLogsDir.resolve(zipFile.getFileName().toString().replace(".zip", ""));
-        ZipUtils.unzip(zipFile.toAbsolutePath().toString(), unzippedMemberDir.toString());
-        FileUtils.deleteQuietly(zipFile.toFile());
-      }
-
-      Path workingDir = Paths.get(System.getProperty("user.dir"));
-      Path exportedLogsZipFile = workingDir
-          .resolve("exportedLogs_" + System.currentTimeMillis() + ".zip").toAbsolutePath();
-
-      logger.info("Zipping into: " + exportedLogsZipFile.toString());
-      ZipUtils.zipDirectory(exportedLogsDir, exportedLogsZipFile);
-      FileUtils.deleteDirectory(tempDir.toFile());
-
-      // TODO:GEODE-2420: warn user if exportedLogsZipFile size > threshold
-      if (isOverDiskSpaceThreshold()) {
-        // append warning to exportedLogsZipFile.toString()??
-      }
-
-      result = ResultBuilder.createInfoResult(exportedLogsZipFile.toString());
-    } catch (Exception ex) {
-      logger.error(ex, ex);
-      result = ResultBuilder.createGemFireErrorResult(ex.getMessage());
-    } finally {
-      ExportLogsFunction.destroyExportLogsRegion(cache);
-    }
-    logger.debug("Exporting logs returning = {}", result);
-    return result;
-  }
-
-  protected static Gfsh getGfsh() {
-    return Gfsh.getCurrentInstance();
-  }
-
-  boolean isOverDiskSpaceThreshold() {
-    return false;
-  }
-
-  /**
-   * after the export logs, will need to copy the tempFile to the desired location and delete the
-   * temp file.
-   */
-  public static class ExportLogsInterceptor extends AbstractCliAroundInterceptor {
-    @Override
-    public Result preExecution(GfshParseResult parseResult) {
-      // the arguments are in the order of it's being declared
-      Map<String, String> arguments = parseResult.getParamValueStrings();
-
-      // validates groupId and memberIds not both set
-      if (arguments.get("group") != null && arguments.get("member") != null) {
-        return ResultBuilder.createUserErrorResult("Can't specify both group and member.");
-      }
-
-      // validate log level
-      String logLevel = arguments.get("log-level");
-      if (StringUtils.isBlank(logLevel) || Level.getLevel(logLevel.toUpperCase()) == null) {
-        return ResultBuilder.createUserErrorResult("Invalid log level: " + logLevel);
-      }
-
-      // validate start date and end date
-      String start = arguments.get("start-time");
-      String end = arguments.get("end-time");
-      if (start != null && end != null) {
-        // need to make sure end is later than start
-        LocalDateTime startTime = ExportLogsFunction.parseTime(start);
-        LocalDateTime endTime = ExportLogsFunction.parseTime(end);
-        if (startTime.isAfter(endTime)) {
-          return ResultBuilder.createUserErrorResult("start-time has to be earlier than end-time.");
-        }
-      }
-
-      // validate onlyLogs and onlyStats
-      boolean onlyLogs = Boolean.parseBoolean(arguments.get("logs-only"));
-      boolean onlyStats = Boolean.parseBoolean(arguments.get("stats-only"));
-      if (onlyLogs && onlyStats) {
-        return ResultBuilder.createUserErrorResult("logs-only and stats-only can't both be true");
-      }
-
-      return ResultBuilder.createInfoResult("");
-    }
-
-    @Override
-    public Result postExecution(GfshParseResult parseResult, Result commandResult, Path tempFile) {
-      // in the command over http case, the command result is in the downloaded temp file
-      if (tempFile != null) {
-        Path dirPath;
-        String dirName = parseResult.getParamValueStrings().get("dir");
-        if (StringUtils.isBlank(dirName)) {
-          dirPath = Paths.get(System.getProperty("user.dir"));
-        } else {
-          dirPath = Paths.get(dirName);
-        }
-        String fileName = "exportedLogs_" + System.currentTimeMillis() + ".zip";
-        File exportedLogFile = dirPath.resolve(fileName).toFile();
-        try {
-          FileUtils.copyFile(tempFile.toFile(), exportedLogFile);
-          FileUtils.deleteQuietly(tempFile.toFile());
-          commandResult = ResultBuilder
-              .createInfoResult("Logs exported to: " + exportedLogFile.getAbsolutePath());
-        } catch (IOException e) {
-          logger.error(e.getMessage(), e);
-          commandResult = ResultBuilder.createGemFireErrorResult(e.getMessage());
-        }
-      } else if (commandResult.getStatus() == Result.Status.OK) {
-        commandResult = ResultBuilder.createInfoResult(
-            "Logs exported to the connected member's file system: " + commandResult.nextLine());
-      }
-      return commandResult;
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommand.java
new file mode 100644
index 0000000..9dd64d7
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommand.java
@@ -0,0 +1,192 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.geode.cache.Region;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.GfshParseResult;
+import org.apache.geode.management.internal.cli.functions.ExportLogsFunction;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.shell.Gfsh;
+import org.apache.geode.management.internal.cli.util.ExportLogsCacheWriter;
+import org.apache.geode.management.internal.configuration.utils.ZipUtils;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class ExportLogsCommand implements CommandMarker {
+
+  private static final Logger logger = LogService.getLogger();
+
+  public static final String FORMAT = "yyyy/MM/dd/HH/mm/ss/SSS/z";
+  public static final String ONLY_DATE_FORMAT = "yyyy/MM/dd";
+
+  private GemFireCacheImpl cache;
+
+  public ExportLogsCommand() {
+    cache = GemFireCacheImpl.getInstance();
+  }
+
+  @CliCommand(value = CliStrings.EXPORT_LOGS, help = CliStrings.EXPORT_LOGS__HELP)
+  @CliMetaData(shellOnly = false, isFileDownloadOverHttp = true,
+      interceptor = "org.apache.geode.management.internal.cli.commands.ExportLogsInterceptor",
+      relatedTopic = {CliStrings.TOPIC_GEODE_SERVER, CliStrings.TOPIC_GEODE_DEBUG_UTIL})
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.READ)
+  public Result exportLogs(
+      @CliOption(key = CliStrings.EXPORT_LOGS__DIR, help = CliStrings.EXPORT_LOGS__DIR__HELP,
+          mandatory = false) String dirName,
+      @CliOption(key = CliStrings.EXPORT_LOGS__GROUP,
+          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CliStrings.EXPORT_LOGS__GROUP__HELP) String[] groups,
+      @CliOption(key = CliStrings.EXPORT_LOGS__MEMBER,
+          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
+          optionContext = ConverterHint.ALL_MEMBER_IDNAME,
+          help = CliStrings.EXPORT_LOGS__MEMBER__HELP) String[] memberIds,
+      @CliOption(key = CliStrings.EXPORT_LOGS__LOGLEVEL,
+          unspecifiedDefaultValue = LogService.DEFAULT_LOG_LEVEL,
+          optionContext = ConverterHint.LOG_LEVEL,
+          help = CliStrings.EXPORT_LOGS__LOGLEVEL__HELP) String logLevel,
+      @CliOption(key = CliStrings.EXPORT_LOGS__UPTO_LOGLEVEL, unspecifiedDefaultValue = "false",
+          help = CliStrings.EXPORT_LOGS__UPTO_LOGLEVEL__HELP) boolean onlyLogLevel,
+      @CliOption(key = CliStrings.EXPORT_LOGS__MERGELOG, unspecifiedDefaultValue = "false",
+          help = CliStrings.EXPORT_LOGS__MERGELOG__HELP) boolean mergeLog,
+      @CliOption(key = CliStrings.EXPORT_LOGS__STARTTIME,
+          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
+          help = CliStrings.EXPORT_LOGS__STARTTIME__HELP) String start,
+      @CliOption(key = CliStrings.EXPORT_LOGS__ENDTIME,
+          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
+          help = CliStrings.EXPORT_LOGS__ENDTIME__HELP) String end,
+      @CliOption(key = CliStrings.EXPORT_LOGS__LOGSONLY, unspecifiedDefaultValue = "false",
+          specifiedDefaultValue = "true",
+          help = CliStrings.EXPORT_LOGS__LOGSONLY__HELP) boolean logsOnly,
+      @CliOption(key = CliStrings.EXPORT_LOGS__STATSONLY, unspecifiedDefaultValue = "false",
+          specifiedDefaultValue = "true",
+          help = CliStrings.EXPORT_LOGS__STATSONLY__HELP) boolean statsOnly) {
+    Result result = null;
+    GemFireCacheImpl cache = this.cache;
+    if (cache == null || cache.isClosed()) {
+      new Exception("KEN: cache is null").printStackTrace();
+      cache = GemFireCacheImpl.getInstance();
+    } else {
+      new Exception("KEN: cache has been created").printStackTrace();
+    }
+    try {
+      Set<DistributedMember> targetMembers =
+          CliUtil.findMembersIncludingLocators(groups, memberIds);
+
+      if (targetMembers.isEmpty()) {
+        return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+      }
+
+      Map<String, Path> zipFilesFromMembers = new HashMap<>();
+      for (DistributedMember server : targetMembers) {
+        Region region = ExportLogsFunction.createOrGetExistingExportLogsRegion(true, cache);
+
+        ExportLogsCacheWriter cacheWriter =
+            (ExportLogsCacheWriter) region.getAttributes().getCacheWriter();
+
+        cacheWriter.startFile(server.getName());
+
+        CliUtil.executeFunction(new ExportLogsFunction(),
+            new ExportLogsFunction.Args(start, end, logLevel, onlyLogLevel, logsOnly, statsOnly),
+            server).getResult();
+        Path zipFile = cacheWriter.endFile();
+        ExportLogsFunction.destroyExportLogsRegion(cache);
+
+        // only put the zipfile in the map if it is not null
+        if (zipFile != null) {
+          logger.info("Received zip file from member {}: {}", server.getId(), zipFile);
+          zipFilesFromMembers.put(server.getId(), zipFile);
+        }
+      }
+
+      if (zipFilesFromMembers.isEmpty()) {
+        return ResultBuilder.createUserErrorResult("No files to be exported.");
+      }
+
+      Path tempDir = Files.createTempDirectory("exportedLogs");
+      // make sure the directory is created, so that even if there is no files unzipped to this dir,
+      // we can
+      // still zip it and send an empty zip file back to the client
+      Path exportedLogsDir = tempDir.resolve("exportedLogs");
+      FileUtils.forceMkdir(exportedLogsDir.toFile());
+
+      for (Path zipFile : zipFilesFromMembers.values()) {
+        Path unzippedMemberDir =
+            exportedLogsDir.resolve(zipFile.getFileName().toString().replace(".zip", ""));
+        ZipUtils.unzip(zipFile.toAbsolutePath().toString(), unzippedMemberDir.toString());
+        FileUtils.deleteQuietly(zipFile.toFile());
+      }
+
+      Path workingDir = Paths.get(System.getProperty("user.dir"));
+      Path exportedLogsZipFile = workingDir
+          .resolve("exportedLogs_" + System.currentTimeMillis() + ".zip").toAbsolutePath();
+
+      logger.info("Zipping into: " + exportedLogsZipFile.toString());
+      ZipUtils.zipDirectory(exportedLogsDir, exportedLogsZipFile);
+      FileUtils.deleteDirectory(tempDir.toFile());
+
+      // TODO:GEODE-2420: warn user if exportedLogsZipFile size > threshold
+      if (isOverDiskSpaceThreshold()) {
+        // append warning to exportedLogsZipFile.toString()??
+      }
+
+      result = ResultBuilder.createInfoResult(exportedLogsZipFile.toString());
+    } catch (Exception ex) {
+      logger.error(ex, ex);
+      result = ResultBuilder.createGemFireErrorResult(ex.getMessage());
+    } finally {
+      ExportLogsFunction.destroyExportLogsRegion(cache);
+    }
+    logger.debug("Exporting logs returning = {}", result);
+    return result;
+  }
+
+  protected static Gfsh getGfsh() {
+    return Gfsh.getCurrentInstance();
+  }
+
+  boolean isOverDiskSpaceThreshold() {
+    return false;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java
new file mode 100644
index 0000000..8427c83
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java
@@ -0,0 +1,108 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor;
+import org.apache.geode.management.internal.cli.GfshParseResult;
+import org.apache.geode.management.internal.cli.functions.ExportLogsFunction;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.util.Map;
+
+/**
+ * after the export logs, will need to copy the tempFile to the desired location and delete the
+ * temp file.
+ */
+public class ExportLogsInterceptor extends AbstractCliAroundInterceptor {
+  private static final Logger logger = LogService.getLogger();
+
+  @Override
+  public Result preExecution(GfshParseResult parseResult) {
+    // the arguments are in the order of it's being declared
+    Map<String, String> arguments = parseResult.getParamValueStrings();
+
+    // validates groupId and memberIds not both set
+    if (arguments.get("group") != null && arguments.get("member") != null) {
+      return ResultBuilder.createUserErrorResult("Can't specify both group and member.");
+    }
+
+    // validate log level
+    String logLevel = arguments.get("log-level");
+    if (StringUtils.isBlank(logLevel) || Level.getLevel(logLevel.toUpperCase()) == null) {
+      return ResultBuilder.createUserErrorResult("Invalid log level: " + logLevel);
+    }
+
+    // validate start date and end date
+    String start = arguments.get("start-time");
+    String end = arguments.get("end-time");
+    if (start != null && end != null) {
+      // need to make sure end is later than start
+      LocalDateTime startTime = ExportLogsFunction.parseTime(start);
+      LocalDateTime endTime = ExportLogsFunction.parseTime(end);
+      if (startTime.isAfter(endTime)) {
+        return ResultBuilder.createUserErrorResult("start-time has to be earlier than end-time.");
+      }
+    }
+
+    // validate onlyLogs and onlyStats
+    boolean onlyLogs = Boolean.parseBoolean(arguments.get("logs-only"));
+    boolean onlyStats = Boolean.parseBoolean(arguments.get("stats-only"));
+    if (onlyLogs && onlyStats) {
+      return ResultBuilder.createUserErrorResult("logs-only and stats-only can't both be true");
+    }
+
+    return ResultBuilder.createInfoResult("");
+  }
+
+  @Override
+  public Result postExecution(GfshParseResult parseResult, Result commandResult, Path tempFile) {
+    // in the command over http case, the command result is in the downloaded temp file
+    if (tempFile != null) {
+      Path dirPath;
+      String dirName = parseResult.getParamValueStrings().get("dir");
+      if (StringUtils.isBlank(dirName)) {
+        dirPath = Paths.get(System.getProperty("user.dir"));
+      } else {
+        dirPath = Paths.get(dirName);
+      }
+      String fileName = "exportedLogs_" + System.currentTimeMillis() + ".zip";
+      File exportedLogFile = dirPath.resolve(fileName).toFile();
+      try {
+        FileUtils.copyFile(tempFile.toFile(), exportedLogFile);
+        FileUtils.deleteQuietly(tempFile.toFile());
+        commandResult = ResultBuilder
+            .createInfoResult("Logs exported to: " + exportedLogFile.getAbsolutePath());
+      } catch (IOException e) {
+        logger.error(e.getMessage(), e);
+        commandResult = ResultBuilder.createGemFireErrorResult(e.getMessage());
+      }
+    } else if (commandResult.getStatus() == Result.Status.OK) {
+      commandResult = ResultBuilder.createInfoResult(
+          "Logs exported to the connected member's file system: " + commandResult.nextLine());
+    }
+    return commandResult;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
index 62026fb..516a9a7 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
@@ -28,7 +28,7 @@ import org.apache.geode.internal.InternalEntity;
 import org.apache.geode.internal.cache.GemFireCacheImpl;
 import org.apache.geode.internal.cache.InternalRegionArguments;
 import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.management.internal.cli.commands.ExportLogCommand;
+import org.apache.geode.management.internal.cli.commands.ExportLogsCommand;
 import org.apache.geode.management.internal.cli.util.ExportLogsCacheWriter;
 import org.apache.geode.management.internal.cli.util.LogExporter;
 import org.apache.geode.management.internal.cli.util.LogFilter;
@@ -207,11 +207,11 @@ public class ExportLogsFunction implements Function, InternalEntity {
     }
 
     try {
-      SimpleDateFormat df = new SimpleDateFormat(ExportLogCommand.FORMAT);
+      SimpleDateFormat df = new SimpleDateFormat(ExportLogsCommand.FORMAT);
       return df.parse(dateString).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
     } catch (ParseException e) {
       try {
-        SimpleDateFormat df = new SimpleDateFormat(ExportLogCommand.ONLY_DATE_FORMAT);
+        SimpleDateFormat df = new SimpleDateFormat(ExportLogsCommand.ONLY_DATE_FORMAT);
         return df.parse(dateString).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
       } catch (ParseException e1) {
         return null;

http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommandTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommandTest.java
new file mode 100644
index 0000000..21843f6
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommandTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+@Category(UnitTest.class)
+public class ExportLogsCommandTest {
+
+  @Mock
+  private Cache cache;
+
+  @Before
+  public void before() throws Exception {
+    // customize behavior
+    this.cache = mock(Cache.class);
+  }
+
+  @Test
+  public void noLogsIsNotOverThreshold() throws Exception {
+//    ExportLogsCommand command = new ExportLogsCommand(this.cache);
+//
+//    assertThat(command.isOverDiskSpaceThreshold()).isFalse();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsDUnitTest.java
index 95edd42..d0180d0 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsDUnitTest.java
@@ -19,8 +19,8 @@ package org.apache.geode.management.internal.cli.commands;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toSet;
-import static org.apache.geode.management.internal.cli.commands.ExportLogCommand.FORMAT;
-import static org.apache.geode.management.internal.cli.commands.ExportLogCommand.ONLY_DATE_FORMAT;
+import static org.apache.geode.management.internal.cli.commands.ExportLogsCommand.FORMAT;
+import static org.apache.geode.management.internal.cli.commands.ExportLogsCommand.ONLY_DATE_FORMAT;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import org.apache.commons.io.FileUtils;

http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptorJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptorJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptorJUnitTest.java
index 97ed686..9709aa6 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptorJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptorJUnitTest.java
@@ -31,14 +31,14 @@ import java.util.Map;
 
 @Category(UnitTest.class)
 public class ExportLogsInterceptorJUnitTest {
-  private ExportLogCommand.ExportLogsInterceptor interceptor;
+  private ExportLogsInterceptor interceptor;
   private GfshParseResult parseResult;
   private Map<String, String> arguments;
   private Result result;
 
   @Before
   public void before() {
-    interceptor = new ExportLogCommand.ExportLogsInterceptor();
+    interceptor = new ExportLogsInterceptor();
     parseResult = Mockito.mock(GfshParseResult.class);
     arguments = new HashMap<>();
     arguments.put("log-level", "info");

http://git-wip-us.apache.org/repos/asf/geode/blob/2bcba1da/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsStatsDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsStatsDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsStatsDUnitTest.java
index de2ea64..92d0268 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsStatsDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsStatsDUnitTest.java
@@ -19,7 +19,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_
 import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
 import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
 import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_ARCHIVE_FILE;
-import static org.apache.geode.management.internal.cli.commands.ExportLogCommand.ONLY_DATE_FORMAT;
+import static org.apache.geode.management.internal.cli.commands.ExportLogsCommand.ONLY_DATE_FORMAT;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import com.google.common.collect.Sets;