You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2017/04/07 19:34:05 UTC

[06/19] geode git commit: GEODE-2420: Add classes to estimated the size of exported logs

GEODE-2420: Add classes to estimated the size of exported logs

- New Function class added with tests
- Code to invoke new function added, but disabled, in ExportLogsCommand
- New option added, but disabled, for specifying size limit for exported
  logs
- Refactoring: extracted the interceptor from ExportLogsCommand
- Refactoring: renamed ExportLogCommand to ExportLogsCommand
- New Serializable class to return the log size estimate to the command
- Tests for the log sizing related classes


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

Branch: refs/heads/feature/GEODE-2632
Commit: 0c15c6e01e7095f61e0e2df9866534f1cf6489cc
Parents: 4a09e88
Author: Ken Howe <kh...@pivotal.io>
Authored: Wed Mar 29 11:10:20 2017 -0700
Committer: Ken Howe <kh...@pivotal.io>
Committed: Tue Apr 4 13:51:07 2017 -0700

----------------------------------------------------------------------
 .../internal/cli/commands/ExportLogCommand.java |  236 ----
 .../cli/commands/ExportLogsCommand.java         |  278 +++++
 .../cli/commands/ExportLogsInterceptor.java     |  109 ++
 .../cli/functions/ExportLogsFunction.java       |    7 +-
 .../cli/functions/ExportedLogsSizeInfo.java     |  107 ++
 .../cli/functions/SizeExportLogsFunction.java   |   87 ++
 .../internal/cli/i18n/CliStrings.java           |    6 +
 .../management/internal/cli/util/LogSizer.java  |  116 ++
 .../cli/commands/ExportLogsCommandTest.java     |  129 +++
 .../cli/commands/ExportLogsDUnitTest.java       |    4 +-
 .../commands/ExportLogsFileSizeLimitTest.java   |   88 ++
 .../ExportLogsInterceptorJUnitTest.java         |    4 +-
 .../cli/commands/ExportLogsStatsDUnitTest.java  |    2 +-
 .../cli/commands/ExportLogsTestSuite.java       |   27 +
 .../cli/commands/LogLevelInterceptorTest.java   |    2 +-
 .../cli/functions/ExportedLogsSizeInfoTest.java |  145 +++
 .../SizeExportLogsFunctionCacheTest.java        |  183 +++
 .../SizeExportLogsFunctionFileTest.java         |  183 +++
 .../cli/functions/SizeExportLogsTestSuite.java  |   29 +
 .../internal/cli/util/LogSizerTest.java         |   99 ++
 .../dunit/rules/GfshShellConnectionRule.java    |    4 +-
 .../sanctionedDataSerializables.txt             | 1066 +++++++++---------
 .../codeAnalysis/sanctionedSerializables.txt    |    1 +
 23 files changed, 2134 insertions(+), 778 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/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 3f147c1..0000000
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogCommand.java
+++ /dev/null
@@ -1,236 +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.util.ExportLogsCacheWriter;
-import org.apache.geode.internal.logging.log4j.LogLevel;
-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.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 {
-  public final static String FORMAT = "yyyy/MM/dd/HH/mm/ss/SSS/z";
-  public final static String ONLY_DATE_FORMAT = "yyyy/MM/dd";
-  private final static Logger logger = LogService.getLogger();
-
-  @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());
-      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;
-  }
-
-  /**
-   * 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) || LogLevel.getLevel(logLevel) == 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/0c15c6e0/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..37cbd71
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommand.java
@@ -0,0 +1,278 @@
+/*
+ * 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.CliUtil;
+import org.apache.geode.management.internal.cli.functions.ExportLogsFunction;
+import org.apache.geode.management.internal.cli.functions.ExportedLogsSizeInfo;
+import org.apache.geode.management.internal.cli.functions.SizeExportLogsFunction;
+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.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.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.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+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 static final Pattern DISK_SPACE_LIMIT_PATTERN = Pattern.compile("(\\d+)([mgtMGT]?)");
+
+  @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) {
+    // @CliOption(key = CliStrings.EXPORT_LOGS__FILESIZELIMIT,
+    // unspecifiedDefaultValue = CliStrings.EXPORT_LOGS__FILESIZELIMIT__UNSPECIFIED_DEFAULT,
+    // specifiedDefaultValue = CliStrings.EXPORT_LOGS__FILESIZELIMIT__SPECIFIED_DEFAULT,
+    // help = CliStrings.EXPORT_LOGS__FILESIZELIMIT__HELP) String fileSizeLimit) {
+    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);
+      }
+
+      if (false) {
+        // TODO: get estimated size of exported logs from all servers first
+        Map<String, Integer> fileSizesFromMembers = new HashMap<>();
+        for (DistributedMember server : targetMembers) {
+          SizeExportLogsFunction.Args args = new SizeExportLogsFunction.Args(start, end, logLevel,
+              onlyLogLevel, logsOnly, statsOnly);
+
+          List<Object> results = (List<Object>) CliUtil
+              .executeFunction(new SizeExportLogsFunction(), args, server).getResult();
+          long estimatedSize = 0;
+          long diskAvailable = 0;
+          long diskSize = 0;
+          List<?> res = (List<?>) results.get(0);
+          if (res.get(0) instanceof ExportedLogsSizeInfo) {
+            ExportedLogsSizeInfo sizeInfo = (ExportedLogsSizeInfo) res.get(0);
+            estimatedSize = sizeInfo.getLogsSize();
+            diskAvailable = sizeInfo.getDiskAvailable();
+            diskSize = sizeInfo.getDiskSize();
+          } else {
+            estimatedSize = 0;
+          }
+
+
+          logger.info("Received file size from member {}: {}", server.getId(), estimatedSize);
+        }
+
+        // TODO: Check log size limits on the locator
+      }
+
+      // get zipped files from all servers next
+      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());
+
+      // try {
+      // isFileSizeCheckEnabledAndWithinLimit(parseFileSizeLimit(fileSizeLimit),
+      // exportedLogsZipFile.toFile());
+      // } catch (IllegalArgumentException e) {
+      // return ResultBuilder.createUserErrorResult("TOO BIG: fileSizeLimit = " + fileSizeLimit);
+      // }
+
+      result = ResultBuilder.createInfoResult(exportedLogsZipFile.toString());
+    } catch (Exception ex) {
+      logger.error(ex.getMessage(), ex);
+      result = ResultBuilder.createGemFireErrorResult(ex.getMessage());
+    } finally {
+      ExportLogsFunction.destroyExportLogsRegion(cache);
+    }
+    logger.debug("Exporting logs returning = {}", result);
+    return result;
+  }
+
+  /**
+   * Returns file size limit in bytes
+   */
+  int parseFileSizeLimit(String fileSizeLimit) {
+    if (StringUtils.isEmpty(fileSizeLimit)) {
+      return 0;
+    }
+
+    int sizeLimit = parseSize(fileSizeLimit);
+    int byteMultiplier = parseByteMultiplier(fileSizeLimit);
+
+    return sizeLimit * byteMultiplier;
+  }
+
+  /**
+   * Throws IllegalArgumentException if file size is over fileSizeLimitBytes
+   */
+  void checkOverDiskSpaceThreshold(int fileSizeLimitBytes, File file) {
+    // TODO:GEODE-2420: warn user if exportedLogsZipFile size > threshold
+    if (FileUtils.sizeOf(file) > fileSizeLimitBytes) {
+      throw new IllegalArgumentException("TOO BIG"); // FileTooBigException
+    }
+  }
+
+  /**
+   * Throws IllegalArgumentException if file size is over fileSizeLimitBytes false == limit is zero
+   * true == file size is less than limit exception == file size is over limit
+   */
+  boolean isFileSizeCheckEnabledAndWithinLimit(int fileSizeLimitBytes, File file) {
+    // TODO:GEODE-2420: warn user if exportedLogsZipFile size > threshold
+    if (fileSizeLimitBytes < 1) {
+      return false;
+    }
+    if (FileUtils.sizeOf(file) < fileSizeLimitBytes) {
+      return true;
+    }
+    throw new IllegalArgumentException("TOO BIG: fileSizeLimit = " + fileSizeLimitBytes
+        + ", fileSize = " + FileUtils.sizeOf(file)); // FileTooBigException
+  }
+
+  static int parseSize(String diskSpaceLimit) {
+    Matcher matcher = DISK_SPACE_LIMIT_PATTERN.matcher(diskSpaceLimit);
+    if (matcher.matches()) {
+      return Integer.parseInt(matcher.group(1));
+    } else {
+      throw new IllegalArgumentException();
+    }
+  }
+
+  static int parseByteMultiplier(String diskSpaceLimit) {
+    Matcher matcher = DISK_SPACE_LIMIT_PATTERN.matcher(diskSpaceLimit);
+    if (!matcher.matches()) {
+      throw new IllegalArgumentException();
+    }
+    switch (matcher.group(2).toLowerCase()) {
+      case "t":
+        return (int) Math.pow(1024, 4);
+      case "g":
+        return (int) Math.pow(1024, 3);
+      case "m":
+      default:
+        return (int) Math.pow(1024, 2);
+    }
+  }
+
+  static final int MEGABYTE = (int) Math.pow(1024, 2);
+  static final int GIGABYTE = (int) Math.pow(1024, 3);
+  static final int TERABYTE = (int) Math.pow(1024, 4);
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/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..dc20da3
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java
@@ -0,0 +1,109 @@
+/*
+ * 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.internal.logging.log4j.LogLevel;
+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) || LogLevel.getLevel(logLevel) == 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/0c15c6e0/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 cbdf1c4..13124c5 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;
@@ -76,6 +76,7 @@ public class ExportLogsFunction implements Function, InternalEntity {
       Args args = (Args) context.getArguments();
       File baseLogFile = null;
       File baseStatsFile = null;
+
       if (args.isIncludeLogs() && !config.getLogFile().toString().isEmpty()) {
         baseLogFile = config.getLogFile().getAbsoluteFile();
       }
@@ -208,11 +209,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/0c15c6e0/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfo.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfo.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfo.java
new file mode 100644
index 0000000..6d56f12
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfo.java
@@ -0,0 +1,107 @@
+/*
+ * 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.functions;
+
+import org.apache.geode.DataSerializable;
+import org.apache.geode.DataSerializer;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public class ExportedLogsSizeInfo implements DataSerializable {
+  private long logsSize;
+  private long diskAvailable;
+  private long diskSize;
+
+  // Used for deserialization only
+  public ExportedLogsSizeInfo() {
+    logsSize = 0;
+    diskAvailable = 0;
+    diskSize = 0;
+  }
+
+  public ExportedLogsSizeInfo(long logsSize, long diskAvailable, long diskSize) {
+    this.logsSize = logsSize;
+    this.diskAvailable = diskAvailable;
+    this.diskSize = diskSize;
+  }
+
+  public long getDiskSize() {
+    return diskSize;
+  }
+
+  public long getDiskAvailable() {
+    return diskAvailable;
+  }
+
+  public long getLogsSize() {
+
+    return logsSize;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    ExportedLogsSizeInfo that = (ExportedLogsSizeInfo) o;
+
+    if (logsSize != that.logsSize) {
+      return false;
+    }
+    if (diskAvailable != that.diskAvailable) {
+      return false;
+    }
+    return diskSize == that.diskSize;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = (int) (logsSize ^ (logsSize >>> 32));
+    result = 31 * result + (int) (diskAvailable ^ (diskAvailable >>> 32));
+    result = 31 * result + (int) (diskSize ^ (diskSize >>> 32));
+    return result;
+  }
+
+  @Override
+  public void toData(DataOutput out) throws IOException {
+    DataSerializer.writeLong(logsSize, out);
+    DataSerializer.writeLong(diskAvailable, out);
+    DataSerializer.writeLong(diskSize, out);
+  }
+
+  @Override
+  public void fromData(DataInput in) throws IOException, ClassNotFoundException {
+    logsSize = DataSerializer.readLong(in);
+    diskAvailable = DataSerializer.readLong(in);
+    diskSize = DataSerializer.readLong(in);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder result = new StringBuilder();
+    result.append("[");
+    result.append("logsSize: " + logsSize);
+    result.append(", diskAvailable: " + diskAvailable);
+    result.append(", diskSize: " + diskSize);
+    result.append("]");
+    return result.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunction.java
new file mode 100644
index 0000000..1718898
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunction.java
@@ -0,0 +1,87 @@
+/*
+ * 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.functions;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.InternalEntity;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.management.internal.cli.util.LogFilter;
+import org.apache.geode.management.internal.cli.util.LogSizer;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Arrays;
+
+public class SizeExportLogsFunction extends ExportLogsFunction implements Function, InternalEntity {
+  private static final Logger LOGGER = LogService.getLogger();
+  private static final long serialVersionUID = 1L;
+
+  protected Cache getCache() {
+    return CacheFactory.getAnyInstance();
+  }
+
+  @Override
+  public void execute(final FunctionContext context) {
+    try {
+      GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
+      DistributionConfig config = cache.getDistributedSystem().getConfig();
+      Args args = (Args) context.getArguments();
+      long diskAvailable = config.getLogFile().getUsableSpace();
+      long diskSize = config.getLogFile().getTotalSpace();
+      long estimatedSize = estimateLogFileSize(cache.getMyId(), config.getLogFile(),
+          config.getStatisticArchiveFile(), args);
+
+      context.getResultSender().lastResult(
+          Arrays.asList(new ExportedLogsSizeInfo(estimatedSize, diskAvailable, diskSize)));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      LOGGER.error(e.getMessage());
+      context.getResultSender().sendException(e);
+    }
+  }
+
+  long estimateLogFileSize(final DistributedMember member, final File logFile,
+      final File statArchive, final Args args) throws ParseException, IOException {
+    LOGGER.info("SizeExportLogsFunction started for member {}", member);
+
+    File baseLogFile = null;
+    File baseStatsFile = null;
+
+    if (args.isIncludeLogs() && !logFile.toString().isEmpty()) {
+      baseLogFile = logFile.getAbsoluteFile();
+    }
+    if (args.isIncludeStats() && !statArchive.toString().isEmpty()) {
+      baseStatsFile = statArchive.getAbsoluteFile();
+    }
+
+    LogFilter logFilter = new LogFilter(args.getLogLevel(), args.isThisLogLevelOnly(),
+        args.getStartTime(), args.getEndTime());
+
+    long estimatedSize = new LogSizer(logFilter, baseLogFile, baseStatsFile).getFilteredSize();
+
+    LOGGER.info("Estimated log file size: " + estimatedSize);
+
+    return estimatedSize;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
index 5b1f089..dfc4cf1 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
@@ -1434,6 +1434,12 @@ public class CliStrings {
   public static final String EXPORT_LOGS__STATSONLY = "stats-only";
   public static final String EXPORT_LOGS__LOGSONLY__HELP = "Whether to only export logs";
   public static final String EXPORT_LOGS__STATSONLY__HELP = "Whether to only export statistics";
+  public static final String EXPORT_LOGS__FILESIZELIMIT = "file-size-limit";
+  public static final String EXPORT_LOGS__FILESIZELIMIT__HELP =
+      "Limits size of the file that can be exported. Specify zero for no limit. Value is in megabytes by default or [m|g|t] may be specified.";
+  public static final String EXPORT_LOGS__FILESIZELIMIT__SPECIFIED_DEFAULT = "0";
+  public static final String EXPORT_LOGS__FILESIZELIMIT__UNSPECIFIED_DEFAULT = "100m";
+
 
   /* export stack-trace command */
   public static final String EXPORT_STACKTRACE = "export stack-traces";

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/LogSizer.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/LogSizer.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/LogSizer.java
new file mode 100644
index 0000000..0a799f6
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/LogSizer.java
@@ -0,0 +1,116 @@
+/*
+ * 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.util;
+
+import static java.util.stream.Collectors.toList;
+
+import org.apache.geode.internal.logging.LogService;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Scanner;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+public class LogSizer {
+  private static final Logger LOGGER = LogService.getLogger();
+
+  private final LogFilter logFilter;
+  private final File baseLogFile;
+  private final File baseStatsFile;
+
+  private long filteredSize;
+
+  /**
+   * @param logFilter the filter that's used to check if we need to accept the file or the logLine
+   * @param baseLogFile if not null, we will export the logs in that directory
+   * @param baseStatsFile if not null, we will export stats in that directory
+   */
+  public LogSizer(LogFilter logFilter, File baseLogFile, File baseStatsFile) throws ParseException {
+    assert logFilter != null;
+    this.logFilter = logFilter;
+    this.baseLogFile = baseLogFile;
+    this.baseStatsFile = baseStatsFile;
+    filteredSize = 0;
+  }
+
+  /**
+   * @return combined size of stat archives and filtered log files in bytes
+   */
+  public long getFilteredSize() throws IOException {
+
+    if (baseLogFile != null) {
+      for (Path logFile : findLogFiles(baseLogFile.toPath().getParent())) {
+        filteredSize += filterAndSize(logFile);
+      }
+    }
+
+    if (baseStatsFile != null) {
+      for (Path statFile : findStatFiles(baseStatsFile.toPath().getParent())) {
+        filteredSize += statFile.toFile().length();
+      }
+    }
+
+    return filteredSize;
+  }
+
+  /**
+   * @return size of file in bytes
+   */
+  protected long filterAndSize(Path originalLogFile) throws FileNotFoundException {
+    long size = 0;
+    Scanner in = new Scanner(originalLogFile.toFile());
+    while (in.hasNextLine()) {
+      String line = in.nextLine();
+
+      LogFilter.LineFilterResult result = this.logFilter.acceptsLine(line);
+
+      if (result == LogFilter.LineFilterResult.REMAINDER_OF_FILE_REJECTED) {
+        break;
+      }
+      size += line.length() + File.separator.length();
+    }
+    return size;
+  }
+
+  protected List<Path> findLogFiles(Path workingDir) throws IOException {
+    Predicate<Path> logFileSelector = (Path file) -> file.toString().toLowerCase().endsWith(".log");
+    return findFiles(workingDir, logFileSelector);
+  }
+
+
+  protected List<Path> findStatFiles(Path workingDir) throws IOException {
+    Predicate<Path> statFileSelector =
+        (Path file) -> file.toString().toLowerCase().endsWith(".gfs");
+    return findFiles(workingDir, statFileSelector);
+  }
+
+  private List<Path> findFiles(Path workingDir, Predicate<Path> fileSelector) throws IOException {
+    Stream<Path> selectedFiles = null;
+    if (!workingDir.toFile().isDirectory()) {
+      return Collections.emptyList();
+    }
+    selectedFiles = Files.list(workingDir).filter(fileSelector).filter(this.logFilter::acceptsFile);
+
+    return selectedFiles.collect(toList());
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/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..a02c07f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsCommandTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.apache.geode.management.internal.cli.commands.ExportLogsCommand.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(UnitTest.class)
+public class ExportLogsCommandTest {
+
+  private ExportLogsCommand createExportLogsCommand(final Cache cache,
+      final DistributedMember distributedMember, final Execution functionExecutor) {
+    return new TestExportLogsCommand(cache, distributedMember, functionExecutor);
+  }
+
+  @Test
+  public void parseSize_sizeWithUnit_shouldReturnSize() throws Exception {
+    assertThat(ExportLogsCommand.parseSize("1000m")).isEqualTo(1000);
+  }
+
+  @Test
+  public void parseSize_sizeWithoutUnit_shouldReturnSize() throws Exception {
+    assertThat(ExportLogsCommand.parseSize("1000")).isEqualTo(1000);
+  }
+
+  @Test
+  public void parseByteMultiplier_sizeWithoutUnit_shouldReturnDefaultUnit() throws Exception {
+    assertThat(ExportLogsCommand.parseByteMultiplier("1000")).isEqualTo(MEGABYTE);
+  }
+
+  @Test
+  public void parseByteMultiplier_sizeWith_m_shouldReturnUnit() throws Exception {
+    assertThat(ExportLogsCommand.parseByteMultiplier("1000m")).isEqualTo(MEGABYTE);
+  }
+
+  @Test
+  public void parseByteMultiplier_sizeWith_g_shouldReturnUnit() throws Exception {
+    assertThat(ExportLogsCommand.parseByteMultiplier("1000g")).isEqualTo(GIGABYTE);
+  }
+
+  @Test
+  public void parseByteMultiplier_sizeWith_t_shouldReturnUnit() throws Exception {
+    assertThat(ExportLogsCommand.parseByteMultiplier("1000t")).isEqualTo(TERABYTE);
+  }
+
+  @Test
+  public void parseByteMultiplier_sizeWith_M_shouldReturnUnit() throws Exception {
+    assertThat(ExportLogsCommand.parseByteMultiplier("1000M")).isEqualTo(MEGABYTE);
+  }
+
+  @Test
+  public void parseByteMultiplier_sizeWith_G_shouldReturnUnit() throws Exception {
+    assertThat(ExportLogsCommand.parseByteMultiplier("1000G")).isEqualTo(GIGABYTE);
+  }
+
+  @Test
+  public void parseByteMultiplier_sizeWith_T_shouldReturnUnit() throws Exception {
+    assertThat(ExportLogsCommand.parseByteMultiplier("1000T")).isEqualTo(TERABYTE);
+  }
+
+  @Test
+  public void parseByteMultiplier_illegalUnit_shouldThrow() throws Exception {
+    assertThatThrownBy(() -> ExportLogsCommand.parseByteMultiplier("1000q"))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void parseSize_garbage_shouldThrow() throws Exception {
+    assertThatThrownBy(() -> ExportLogsCommand.parseSize("bizbap"))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void parseByteMultiplier_garbage_shouldThrow() throws Exception {
+    assertThatThrownBy(() -> ExportLogsCommand.parseByteMultiplier("bizbap"))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Ignore
+  @Test
+  public void sizeFromMember_withinLimits() throws Exception {
+    final Cache mockCache = mock(Cache.class);
+    final DistributedMember mockDistributedMember = mock(DistributedMember.class);
+    final Execution mockFuntionExecutor = mock(Execution.class);
+    final ResultCollector mockResultCollector = mock(ResultCollector.class);
+
+    final ExportLogsCommand cmd =
+        createExportLogsCommand(mockCache, mockDistributedMember, mockFuntionExecutor);
+    // cmd.exportLogs();
+  }
+
+  private static class TestExportLogsCommand extends ExportLogsCommand {
+
+    private final Cache cache;
+    private final DistributedMember distributedMember;
+    private final Execution functionExecutor;
+
+    public TestExportLogsCommand(final Cache cache, final DistributedMember distributedMember,
+        final Execution functionExecutor) {
+      assert cache != null;
+      this.cache = cache;
+      this.distributedMember = distributedMember;
+      this.functionExecutor = functionExecutor;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/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/0c15c6e0/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsFileSizeLimitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsFileSizeLimitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsFileSizeLimitTest.java
new file mode 100644
index 0000000..ec2bcfe
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsFileSizeLimitTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.apache.geode.management.internal.cli.commands.ExportLogsCommand.MEGABYTE;
+import static org.assertj.core.api.Assertions.*;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+@Category(IntegrationTest.class)
+public class ExportLogsFileSizeLimitTest {
+
+  private File dir;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @Before
+  public void before() throws Exception {
+    this.dir = this.temporaryFolder.getRoot();
+  }
+
+  @Test
+  public void sizeOverLimitThrows() throws Exception {
+    File file = new File(this.dir, this.testName.getMethodName());
+    fillUpFile(file, MEGABYTE * 2);
+
+    ExportLogsCommand exportLogsCommand = new ExportLogsCommand();
+
+    assertThatThrownBy(
+        () -> exportLogsCommand.isFileSizeCheckEnabledAndWithinLimit(MEGABYTE, file));
+  }
+
+  @Test
+  public void sizeLessThanLimitIsOk() throws Exception {
+    File file = new File(this.dir, this.testName.getMethodName());
+    fillUpFile(file, MEGABYTE / 2);
+
+    ExportLogsCommand exportLogsCommand = new ExportLogsCommand();
+
+    assertThat(exportLogsCommand.isFileSizeCheckEnabledAndWithinLimit(MEGABYTE, file)).isTrue();
+  }
+
+  @Test
+  public void sizeZeroIsUnlimitedSize() throws Exception {
+    File file = new File(this.dir, this.testName.getMethodName());
+    fillUpFile(file, MEGABYTE * 2);
+
+    ExportLogsCommand exportLogsCommand = new ExportLogsCommand();
+
+    assertThat(exportLogsCommand.isFileSizeCheckEnabledAndWithinLimit(0, file)).isFalse();
+  }
+
+  private void fillUpFile(File file, int sizeInBytes) throws IOException {
+    PrintWriter writer = new PrintWriter(file, "UTF-8");
+    while (FileUtils.sizeOf(file) < sizeInBytes) {
+      writer.println("this is a line of data in the file");
+    }
+    writer.close();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/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 573701f..ec8fdb6 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/0c15c6e0/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 5a4d274..44a0362 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;

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsTestSuite.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsTestSuite.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsTestSuite.java
new file mode 100644
index 0000000..90a92f3
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsTestSuite.java
@@ -0,0 +1,27 @@
+/*
+ * 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.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * All of the JUnit, DUnit and Integration tests for gfsh command export logs.
+ */
+@Suite.SuiteClasses({ExportLogsCommandTest.class, ExportLogsFileSizeLimitTest.class,
+    ExportLogsIntegrationTest.class, ExportLogsDUnitTest.class,})
+@RunWith(Suite.class)
+public class ExportLogsTestSuite {
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/LogLevelInterceptorTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/LogLevelInterceptorTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/LogLevelInterceptorTest.java
index 41b9715..bcbe07c 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/LogLevelInterceptorTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/LogLevelInterceptorTest.java
@@ -41,7 +41,7 @@ public class LogLevelInterceptorTest {
 
   @Before
   public void before() {
-    interceptors.add(new ExportLogCommand.ExportLogsInterceptor());
+    interceptors.add(new ExportLogsInterceptor());
     interceptors.add(new ConfigCommands.AlterRuntimeInterceptor());
     interceptors.add(new MiscellaneousCommands.ChangeLogLevelInterceptor());
 

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfoTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfoTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfoTest.java
new file mode 100644
index 0000000..017d70d
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/ExportedLogsSizeInfoTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.functions;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+
+@Category(UnitTest.class)
+public class ExportedLogsSizeInfoTest {
+  @Before
+  public void setUp() throws Exception {
+
+  }
+
+  @After
+  public void tearDown() throws Exception {
+
+  }
+
+  @Test
+  public final void testExportedLogsSizeInfoConstructor() {
+    ExportedLogsSizeInfo sizeDetail = new ExportedLogsSizeInfo(1L, 11L, 111L);
+    assertThat(sizeDetail).isNotNull();
+    assertThat(sizeDetail.getLogsSize()).isEqualTo(1L);
+    assertThat(sizeDetail.getDiskAvailable()).isEqualTo(11L);
+    assertThat(sizeDetail.getDiskSize()).isEqualTo(111L);
+  }
+
+  @Test
+  public final void testExportedLogsSizeInfoZeroArgConstructor() {
+    ExportedLogsSizeInfo sizeDetail = new ExportedLogsSizeInfo();
+    assertThat(sizeDetail).isNotNull();
+    assertThat(sizeDetail.getLogsSize()).isEqualTo(0L);
+    assertThat(sizeDetail.getDiskAvailable()).isEqualTo(0L);
+    assertThat(sizeDetail.getDiskSize()).isEqualTo(0L);
+  }
+
+  @Test
+  public void equals_returnsTrueForTwoInstancesWithTheSameFieldValues() throws Exception {
+    ExportedLogsSizeInfo sizeDetail1 = new ExportedLogsSizeInfo(2L, 22L, 222L);
+    ExportedLogsSizeInfo sizeDetail2 = new ExportedLogsSizeInfo(2L, 22L, 222L);
+    assertThat(sizeDetail1.equals(sizeDetail1)).isTrue();
+    assertThat(sizeDetail1.equals(sizeDetail2)).isTrue();
+    assertThat(sizeDetail2.equals(sizeDetail1)).isTrue();
+  }
+
+  @Test
+  public void equals_returnsFalseWhenLogsSizeDiffers() throws Exception {
+    ExportedLogsSizeInfo sizeDetail1 = new ExportedLogsSizeInfo(3L, 33L, 333L);
+    ExportedLogsSizeInfo sizeDetail2 = new ExportedLogsSizeInfo(33L, 33L, 333L);
+    assertThat(sizeDetail1.equals(sizeDetail2)).isFalse();
+    assertThat(sizeDetail2.equals(sizeDetail1)).isFalse();
+  }
+
+  @Test
+  public void equals_returnsFalseWhenAvailableDiskDiffers() throws Exception {
+    ExportedLogsSizeInfo sizeDetail1 = new ExportedLogsSizeInfo(4L, 44L, 444L);
+    ExportedLogsSizeInfo sizeDetail2 = new ExportedLogsSizeInfo(4L, 4L, 444L);
+    assertThat(sizeDetail1.equals(sizeDetail2)).isFalse();
+    assertThat(sizeDetail2.equals(sizeDetail1)).isFalse();
+  }
+
+  @Test
+  public void equals_returnsFalseWheneDiskSizeDiffers() throws Exception {
+    ExportedLogsSizeInfo sizeDetail1 = new ExportedLogsSizeInfo(5L, 55L, 555L);
+    ExportedLogsSizeInfo sizeDetail2 = new ExportedLogsSizeInfo(5L, 55L, 55L);
+    assertThat(sizeDetail1.equals(sizeDetail2)).isFalse();
+    assertThat(sizeDetail2.equals(sizeDetail1)).isFalse();
+  }
+
+  @Test
+  public void equals_returnsFalseForComparisonWithNullObject() throws Exception {
+    ExportedLogsSizeInfo sizeDetail1 = new ExportedLogsSizeInfo(6L, 66L, 666L);
+    ExportedLogsSizeInfo sizeDetail2 = null;
+    assertThat(sizeDetail1.equals(sizeDetail2)).isFalse();
+  }
+
+  @Test
+  public final void testClassInequality() {
+    ExportedLogsSizeInfo sizeDeatai1 = new ExportedLogsSizeInfo(7L, 77L, 777L);
+    String sizeDetail2 = sizeDeatai1.toString();
+    assertThat(sizeDeatai1.equals(sizeDetail2)).isFalse();
+    assertThat(sizeDetail2.equals(sizeDeatai1)).isFalse();
+  }
+
+  @Test
+  public void testHashCode() throws Exception {
+    ExportedLogsSizeInfo sizeDetail1 = new ExportedLogsSizeInfo();
+    ExportedLogsSizeInfo sizeDetail2 = new ExportedLogsSizeInfo(8L, 88L, 888L);
+    ExportedLogsSizeInfo sizeDetail3 = new ExportedLogsSizeInfo(88L, 8L, 888L);
+
+    assertThat(sizeDetail1.hashCode()).isNotEqualTo(sizeDetail2.hashCode());
+    assertThat(sizeDetail1.hashCode()).isNotEqualTo(sizeDetail3.hashCode());
+    assertThat(sizeDetail2.hashCode()).isNotEqualTo(sizeDetail3.hashCode());
+
+    assertThat(sizeDetail1.hashCode()).isEqualTo(0);
+    assertThat(sizeDetail2.hashCode()).isEqualTo(11304);
+    assertThat(sizeDetail3.hashCode()).isEqualTo(85704);
+
+  }
+
+  @Test
+  public void deserialization_setsFieldsToOriginalUnserializedValues() throws Exception {
+    ExportedLogsSizeInfo sizeDetail = new ExportedLogsSizeInfo(9L, 99L, 999L);
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    DataOutput out = new DataOutputStream(baos);
+    sizeDetail.toData(out);
+    ExportedLogsSizeInfo sizeDetailIn = new ExportedLogsSizeInfo();
+    sizeDetailIn.fromData(new DataInputStream(new ByteArrayInputStream(baos.toByteArray())));
+
+    assertThat(sizeDetailIn).isEqualTo(sizeDetail);
+  }
+
+  @Test
+  public void testToString() throws Exception {
+    ExportedLogsSizeInfo sizeDetail = new ExportedLogsSizeInfo(10L, 100L, 1000L);
+    assertThat(sizeDetail.toString())
+        .isEqualTo("[logsSize: 10, diskAvailable: 100, diskSize: 1000]");
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionCacheTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionCacheTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionCacheTest.java
new file mode 100644
index 0000000..8de605f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionCacheTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.functions;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.apache.geode.distributed.ConfigurationProperties.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.cache.execute.ResultSender;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.execute.FunctionContextImpl;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+@Category(IntegrationTest.class)
+public class SizeExportLogsFunctionCacheTest {
+
+  private Cache cache;
+
+  private SizeExportLogsFunction.Args nonFilteringArgs;
+  private TestResultSender resultSender;
+  private FunctionContext functionContext;
+  private File dir;
+  private DistributedMember member;
+  File logFile;
+  File statFile;
+  String name;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @Before
+  public void before() throws Throwable {
+    name = testName.getMethodName();
+
+    this.dir = this.temporaryFolder.getRoot();
+    logFile = new File(dir, name + ".log");
+    statFile = new File(dir, name + ".gfs");
+
+    this.nonFilteringArgs = new ExportLogsFunction.Args(null, null, null, false, false, false);
+    functionContext = new FunctionContextImpl("functionId", nonFilteringArgs, resultSender);
+
+  }
+
+  @After
+  public void after() throws Exception {
+    if (this.cache != null) {
+      this.cache.close();
+    }
+    FileUtils.deleteDirectory(dir);
+  }
+
+  @Test
+  public void withFiles_returnsCombinedSizeResult() throws Throwable {
+    Properties config = new Properties();
+    config.setProperty(NAME, name);
+    config.setProperty(LOCATORS, "");
+    config.setProperty(MCAST_PORT, "0");
+    config.setProperty(LOG_FILE, logFile.getAbsolutePath());
+    config.setProperty(STATISTIC_ARCHIVE_FILE, statFile.getAbsolutePath());
+
+    this.cache = new CacheFactory(config).create();
+    TestResultSender resultSender = new TestResultSender();
+    FunctionContext context = new FunctionContextImpl("functionId", nonFilteringArgs, resultSender);
+
+    // log and stat files sizes are not constant with a real cache running, so check for the sizer
+    // estimate within a range
+    long initalFileSizes = FileUtils.sizeOf(logFile) + FileUtils.sizeOf(statFile);
+    new SizeExportLogsFunction().execute(context);
+    long finalFileSizes = FileUtils.sizeOf(logFile) + FileUtils.sizeOf(statFile);
+    getAndVerifySizeEstimate(resultSender, initalFileSizes, finalFileSizes);
+  }
+
+  @Test
+  public void noFiles_returnsZeroResult() throws Throwable {
+    Properties config = new Properties();
+    config.setProperty(NAME, name);
+    config.setProperty(LOCATORS, "");
+    config.setProperty(MCAST_PORT, "0");
+
+    this.cache = new CacheFactory(config).create();
+
+    TestResultSender resultSender = new TestResultSender();
+    FunctionContext context = new FunctionContextImpl("functionId", nonFilteringArgs, resultSender);
+
+    new SizeExportLogsFunction().execute(context);
+    getAndVerifySizeEstimate(resultSender, 0L);
+  }
+
+  private void getAndVerifySizeEstimate(TestResultSender resultSender, long expectedSize)
+      throws Throwable {
+    getAndVerifySizeEstimate(resultSender, expectedSize, expectedSize);
+  }
+
+  private void getAndVerifySizeEstimate(TestResultSender resultSender, long minExpected,
+      long maxExpected) throws Throwable {
+    List<?> results = resultSender.getResults();
+
+    assertThat(results).isNotNull();
+    assertThat(results.size()).isEqualTo(1);
+    List<?> result = (List<?>) results.get(0);
+    assertThat(result).isNotNull();
+    assertThat(((ExportedLogsSizeInfo) result.get(0)).getLogsSize())
+        .isGreaterThanOrEqualTo(minExpected).isLessThanOrEqualTo(maxExpected);
+  }
+
+  @Test
+  public void withFunctionError_shouldThrow() throws Throwable {
+    Properties config = new Properties();
+    config.setProperty(NAME, name);
+    config.setProperty(LOCATORS, "");
+    config.setProperty(MCAST_PORT, "0");
+
+    this.cache = new CacheFactory().create();
+
+    TestResultSender resultSender = new TestResultSender();
+    FunctionContext context = new FunctionContextImpl("functionId", null, resultSender);
+
+    new SizeExportLogsFunction().execute(context);
+    assertThatThrownBy(() -> resultSender.getResults()).isInstanceOf(NullPointerException.class);
+  }
+
+  private static class TestResultSender implements ResultSender {
+
+    private final List<Object> results = new LinkedList<Object>();
+
+    private Throwable t;
+
+    protected List<Object> getResults() throws Throwable {
+      if (t != null) {
+        throw t;
+      }
+      return Collections.unmodifiableList(results);
+    }
+
+    @Override
+    public void lastResult(final Object lastResult) {
+      results.add(lastResult);
+    }
+
+    @Override
+    public void sendResult(final Object oneResult) {
+      results.add(oneResult);
+    }
+
+    @Override
+    public void sendException(final Throwable t) {
+      this.t = t;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionFileTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionFileTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionFileTest.java
new file mode 100644
index 0000000..87ad7d2
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsFunctionFileTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.functions;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.management.internal.cli.functions.ExportLogsFunction.Args;
+import org.apache.commons.io.FileUtils;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+@Category(IntegrationTest.class)
+public class SizeExportLogsFunctionFileTest {
+
+  private File dir;
+  private DistributedMember member;
+  private SizeExportLogsFunction.Args nonFilteringArgs;
+  private FunctionContext functionContext;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @Before
+  public void before() throws Exception {
+    this.dir = this.temporaryFolder.getRoot();
+    this.member = mock(DistributedMember.class);
+    this.nonFilteringArgs = new Args(null, null, null, false, false, false);
+  }
+
+  @After
+  public void after() throws Exception {
+    FileUtils.deleteDirectory(dir);
+  }
+
+  @Test
+  public void bothFiles_returnsCombinedSize() throws Exception {
+    List<File> logFiles =
+        createLogFiles(new File(dir.getName(), testName.getMethodName()), 1, 1, FileUtils.ONE_KB);
+    File logFile = logFiles.get(0);
+    long logFileSize = FileUtils.sizeOf(logFiles.get(0));
+
+    List<File> statFiles =
+        createStatFiles(new File(dir.getName(), testName.getMethodName()), 1, 1, FileUtils.ONE_KB);
+    File statArchive = statFiles.get(0);
+    long statFileSize = FileUtils.sizeOf(statArchive);
+
+    SizeExportLogsFunction function = new SizeExportLogsFunction();
+    assertThat(function.estimateLogFileSize(this.member, logFile, statArchive, nonFilteringArgs))
+        .isEqualTo(logFileSize + statFileSize);
+  }
+
+  private long expectedSize;
+
+  @Test
+  public void manyFiles_returnsCombinedSize() throws Exception {
+    expectedSize = 0;
+    List<File> logFiles =
+        createLogFiles(new File(dir.getName(), testName.getMethodName()), 1, 3, FileUtils.ONE_KB);
+    logFiles.forEach((file) -> {
+      expectedSize += FileUtils.sizeOf(file);
+    });
+
+    List<File> statFiles = createStatFiles(new File(dir.getName(), testName.getMethodName()), 1, 2,
+        FileUtils.ONE_KB * 2);
+    statFiles.forEach((file) -> {
+      expectedSize += FileUtils.sizeOf(file);
+    });
+
+    SizeExportLogsFunction function = new SizeExportLogsFunction();
+    assertThat(function.estimateLogFileSize(this.member, logFiles.get(0), statFiles.get(0),
+        nonFilteringArgs)).isEqualTo(expectedSize);
+  }
+
+  @Test
+  public void emptyFiles_returnsZeroSize() throws Exception {
+    List<File> logFiles =
+        createLogFiles(new File(dir.getName(), testName.getMethodName()), 1, 3, 0);
+
+    List<File> statFiles =
+        createStatFiles(new File(dir.getName(), testName.getMethodName()), 1, 2, 0);
+    SizeExportLogsFunction function = new SizeExportLogsFunction();
+    assertThat(function.estimateLogFileSize(this.member, logFiles.get(0), statFiles.get(0),
+        nonFilteringArgs)).isEqualTo(0);
+  }
+
+  @Test
+  public void nullFiles_returnsZeroSize() throws Exception {
+    File nullLogFile = new File(dir.getPath(), "nullLogFile");
+    File nullStatFile = new File(dir.getPath(), "nullStatFile");
+    SizeExportLogsFunction function = new SizeExportLogsFunction();
+    assertThat(
+        function.estimateLogFileSize(this.member, nullLogFile, nullStatFile, nonFilteringArgs))
+            .isEqualTo(0);
+  }
+
+  private List<File> createLogFiles(File logFile, int mainId, int numberOfFiles, long sizeOfFile)
+      throws IOException {
+    List<File> files = new ArrayList<>();
+    for (int i = 0; i < numberOfFiles; i++) {
+      String name =
+          baseName(logFile.getName()) + "-" + formatId(mainId) + "-" + formatId(i + 1) + ".log";
+      File file = createFile(name, sizeOfFile, true);
+      files.add(file);
+    }
+    return files;
+  }
+
+  private List<File> createStatFiles(File logFile, int mainId, int numberOfFiles, long sizeOfFile)
+      throws IOException {
+    List<File> files = new ArrayList<>();
+    for (int i = 0; i < numberOfFiles; i++) {
+      String name =
+          baseName(logFile.getName()) + "-" + formatId(mainId) + "-" + formatId(i + 1) + ".gfs";
+      File file = createFile(name, sizeOfFile, false);
+      files.add(file);
+    }
+    return files;
+  }
+
+  private String baseName(String logFileName) {
+    // base log file: myfile.log
+    // mainId childId for rolling
+    // myfile-01-01.log
+    // myfile-01-02.log
+    // pass in myfile.log
+    // return myfile
+    return null;
+  }
+
+  private String formatId(final int id) {
+    return String.format("%02d", id);
+  }
+
+  private File createFile(String name, long sizeInBytes, boolean lineFeed) throws IOException {
+    File file = new File(this.dir, name);
+    fillUpFile(file, sizeInBytes, lineFeed);
+    return file;
+  }
+
+  private void fillUpFile(File file, long sizeInBytes, boolean lineFeed) throws IOException {
+    PrintWriter writer = new PrintWriter(file, "UTF-8");
+    while (FileUtils.sizeOf(file) < sizeInBytes) {
+      writer.print("this is a line of data in the file");
+      if (lineFeed) {
+        writer.println();
+      }
+    }
+    writer.close();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c15c6e0/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsTestSuite.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsTestSuite.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsTestSuite.java
new file mode 100644
index 0000000..e70a750
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/SizeExportLogsTestSuite.java
@@ -0,0 +1,29 @@
+/*
+ * 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.functions;
+
+import org.apache.geode.management.internal.cli.util.LogSizerTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * JUnit, DUnit and Integration tests for SizeExportLogsFunction.
+ */
+@Suite.SuiteClasses({SizeExportLogsFunctionCacheTest.class, SizeExportLogsFunctionFileTest.class,
+    LogSizerTest.class, ExportedLogsSizeInfoTest.class})
+@RunWith(Suite.class)
+public class SizeExportLogsTestSuite {
+
+}