This is an automated email from the ASF dual-hosted git repository.

mmuzaf pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 0591cb337b8 IGNITE-16732 Add configurable ignite log and metrics 
messages (#9918)
0591cb337b8 is described below

commit 0591cb337b834431862a340f220962cb9863a7c0
Author: Maxim Muzafarov <maxmu...@gmail.com>
AuthorDate: Sun Apr 10 22:49:14 2022 +0300

    IGNITE-16732 Add configurable ignite log and metrics messages (#9918)
---
 assembly/dependencies-apache-ignite-lgpl.xml       |    1 +
 assembly/dependencies-apache-ignite-slim.xml       |    1 +
 assembly/dependencies-apache-ignite.xml            |    1 +
 .../org/apache/ignite/internal/IgniteKernal.java   | 1024 +-------------------
 .../org/apache/ignite/internal/IgnitionEx.java     |    3 +-
 .../internal/plugin/IgniteLogInfoProvider.java     |   66 ++
 .../internal/plugin/IgniteLogInfoProviderImpl.java | 1018 +++++++++++++++++++
 .../IgniteCacheDatabaseSharedManager.java          |   11 +-
 .../apache/ignite/internal/util/IgniteUtils.java   |  110 ++-
 .../ignite/thread/IgniteThreadPoolSizeTest.java    |    4 +-
 modules/extdata/logo/licenses/apache-2.0.txt       |  202 ++++
 modules/extdata/logo/pom.xml                       |  111 +++
 .../ignite/internal/IgniteExtendedLogoTest.java    |   42 +
 .../plugin/IgniteExtLogInfoProviderImpl.java       |   47 +
 .../testsuites/IgniteLogoExtensionTestSuite.java   |   32 +
 ...he.ignite.internal.plugin.IgniteLogInfoProvider |    1 +
 pom.xml                                            |    1 +
 17 files changed, 1671 insertions(+), 1004 deletions(-)

diff --git a/assembly/dependencies-apache-ignite-lgpl.xml 
b/assembly/dependencies-apache-ignite-lgpl.xml
index 68ae4d3e010..44cd9ad26dd 100644
--- a/assembly/dependencies-apache-ignite-lgpl.xml
+++ b/assembly/dependencies-apache-ignite-lgpl.xml
@@ -120,6 +120,7 @@
                 <exclude>${project.groupId}:ignite-extdata-p2p</exclude>
                 <exclude>${project.groupId}:ignite-extdata-uri</exclude>
                 <exclude>${project.groupId}:ignite-extdata-uri-dep</exclude>
+                <exclude>${project.groupId}:ignite-extdata-logo</exclude>
                 <exclude>${project.groupId}:ignite-examples</exclude>
                 <exclude>${project.groupId}:ignite-indexing</exclude>
                 <exclude>${project.groupId}:ignite-visor-console</exclude>
diff --git a/assembly/dependencies-apache-ignite-slim.xml 
b/assembly/dependencies-apache-ignite-slim.xml
index 08c33072cfc..c5795e8fc0b 100644
--- a/assembly/dependencies-apache-ignite-slim.xml
+++ b/assembly/dependencies-apache-ignite-slim.xml
@@ -120,6 +120,7 @@
                 <exclude>${project.groupId}:ignite-extdata-p2p</exclude>
                 <exclude>${project.groupId}:ignite-extdata-uri</exclude>
                 <exclude>${project.groupId}:ignite-extdata-uri-dep</exclude>
+                <exclude>${project.groupId}:ignite-extdata-logo</exclude>
                 <exclude>${project.groupId}:ignite-examples</exclude>
                 <exclude>${project.groupId}:ignite-indexing</exclude>
                 <exclude>${project.groupId}:ignite-visor-console</exclude>
diff --git a/assembly/dependencies-apache-ignite.xml 
b/assembly/dependencies-apache-ignite.xml
index 28fa77cd4df..31ae5068727 100644
--- a/assembly/dependencies-apache-ignite.xml
+++ b/assembly/dependencies-apache-ignite.xml
@@ -121,6 +121,7 @@
                 <exclude>${project.groupId}:ignite-extdata-p2p</exclude>
                 <exclude>${project.groupId}:ignite-extdata-uri</exclude>
                 <exclude>${project.groupId}:ignite-extdata-uri-dep</exclude>
+                <exclude>${project.groupId}:ignite-extdata-logo</exclude>
                 <exclude>${project.groupId}:ignite-examples</exclude>
                 <exclude>${project.groupId}:ignite-indexing</exclude>
                 <exclude>${project.groupId}:ignite-visor-console</exclude>
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java 
b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 2e7c101b2f6..c5537db95cf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -18,37 +18,25 @@
 package org.apache.ignite.internal;
 
 import java.io.Externalizable;
-import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InvalidObjectException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
-import java.io.UncheckedIOException;
 import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
 import java.lang.reflect.Constructor;
 import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Properties;
 import java.util.UUID;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -91,7 +79,6 @@ import org.apache.ignite.PersistenceMetrics;
 import org.apache.ignite.cache.affinity.Affinity;
 import org.apache.ignite.cluster.BaselineNode;
 import org.apache.ignite.cluster.ClusterGroup;
-import org.apache.ignite.cluster.ClusterMetrics;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.cluster.ClusterState;
 import org.apache.ignite.compute.ComputeJob;
@@ -99,8 +86,6 @@ import org.apache.ignite.configuration.AtomicConfiguration;
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.CollectionConfiguration;
-import org.apache.ignite.configuration.DataRegionConfiguration;
-import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.MemoryConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
@@ -128,6 +113,8 @@ import 
org.apache.ignite.internal.managers.loadbalancer.GridLoadBalancerManager;
 import org.apache.ignite.internal.managers.systemview.GridSystemViewManager;
 import org.apache.ignite.internal.managers.tracing.GridTracingManager;
 import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
+import org.apache.ignite.internal.plugin.IgniteLogInfoProvider;
+import org.apache.ignite.internal.plugin.IgniteLogInfoProviderImpl;
 import org.apache.ignite.internal.processors.GridProcessor;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.affinity.GridAffinityProcessor;
@@ -141,8 +128,6 @@ import 
org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
 import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
 import 
org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccProcessorImpl;
-import org.apache.ignite.internal.processors.cache.persistence.DataRegion;
-import 
org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
 import 
org.apache.ignite.internal.processors.cache.persistence.filename.PdsConsistentIdProcessor;
 import 
org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
 import org.apache.ignite.internal.processors.closure.GridClosureProcessor;
@@ -173,7 +158,6 @@ import 
org.apache.ignite.internal.processors.platform.plugin.PlatformPluginProce
 import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
 import org.apache.ignite.internal.processors.pool.PoolProcessor;
 import org.apache.ignite.internal.processors.port.GridPortProcessor;
-import org.apache.ignite.internal.processors.port.GridPortRecord;
 import org.apache.ignite.internal.processors.query.GridQueryProcessor;
 import org.apache.ignite.internal.processors.resource.GridResourceProcessor;
 import 
org.apache.ignite.internal.processors.resource.GridSpringResourceContext;
@@ -226,23 +210,18 @@ import org.apache.ignite.plugin.PluginNotFoundException;
 import org.apache.ignite.plugin.PluginProvider;
 import org.apache.ignite.spi.IgniteSpi;
 import org.apache.ignite.spi.IgniteSpiVersionCheckException;
-import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.isolated.IsolatedDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
 import org.apache.ignite.spi.tracing.TracingConfigurationManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import static java.util.Optional.ofNullable;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_CONFIG_URL;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_DAEMON;
-import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_NO_ASCII;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_OPTIMIZED_MARSHALLER_USE_DEFAULT_SUID;
-import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_REST_START_ON_CLIENT;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_STARVATION_CHECK_INTERVAL;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_SUCCESS_FILE;
 import static org.apache.ignite.IgniteSystemProperties.getBoolean;
 import static org.apache.ignite.internal.GridKernalState.DISCONNECTED;
 import static org.apache.ignite.internal.GridKernalState.STARTED;
@@ -288,13 +267,10 @@ import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SHUTDOWN_POLI
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SPI_CLASS;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_TX_CONFIG;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_USER_NAME;
-import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
 import static org.apache.ignite.internal.IgniteVersionUtils.BUILD_TSTAMP_STR;
 import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
-import static org.apache.ignite.internal.IgniteVersionUtils.REV_HASH_STR;
 import static org.apache.ignite.internal.IgniteVersionUtils.VER;
 import static org.apache.ignite.internal.IgniteVersionUtils.VER_STR;
-import static 
org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager.INTERNAL_DATA_REGION_NAMES;
 import static org.apache.ignite.lifecycle.LifecycleEventType.AFTER_NODE_START;
 import static org.apache.ignite.lifecycle.LifecycleEventType.BEFORE_NODE_START;
 import static org.apache.ignite.mxbean.IgniteMXBean.ACTIVE_DESC;
@@ -379,9 +355,6 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
     /** System line separator. */
     public static final String NL = U.nl();
 
-    /** System megabyte. */
-    private static final int MEGABYTE = 1024 * 1024;
-
     /**
      * Default interval of checking thread pool state for the starvation. Will 
be used only if the
      * {@link IgniteSystemProperties#IGNITE_STARVATION_CHECK_INTERVAL} system 
property is not set.
@@ -407,6 +380,9 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
     /** @see IgniteSystemProperties#IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP */
     public static final boolean DFLT_LOG_CLASSPATH_CONTENT_ON_STARTUP = true;
 
+    /** Ignite node information provider. */
+    private final IgniteLogInfoProvider info = loadInfoProvider();
+
     /** Currently used instance of JVM pause detector thread. See {@link 
LongJVMPauseDetector} for details. */
     private LongJVMPauseDetector longJVMPauseDetector;
 
@@ -591,7 +567,7 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
     }
 
     /** @return String representation of the uptime. */
-    String upTimeFormatted() {
+    public String upTimeFormatted() {
         return X.timeSpan2DHMSM(upTime());
     }
 
@@ -858,100 +834,6 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
         }
     }
 
-    /**
-     * @param clsPathEntry Classpath string to process.
-     * @param clsPathContent StringBuilder to attach path to.
-     */
-    private void ackClassPathEntry(String clsPathEntry, SB clsPathContent) {
-        File clsPathElementFile = new File(clsPathEntry);
-
-        if (clsPathElementFile.isDirectory())
-            clsPathContent.a(clsPathEntry).a(";");
-        else {
-            String extension = clsPathEntry.length() >= 4
-                ? clsPathEntry.substring(clsPathEntry.length() - 
4).toLowerCase()
-                : null;
-
-            if (".jar".equals(extension) || ".zip".equals(extension))
-                clsPathContent.a(clsPathEntry).a(";");
-        }
-    }
-
-    /**
-     * @param clsPathEntry Classpath string to process.
-     * @param clsPathContent StringBuilder to attach path to.
-     */
-    private void ackClassPathWildCard(String clsPathEntry, SB clsPathContent) {
-        final int lastSeparatorIdx = clsPathEntry.lastIndexOf(File.separator);
-
-        final int asteriskIdx = clsPathEntry.indexOf('*');
-
-        //just to log possibly incorrent entries to err
-        if (asteriskIdx >= 0 && asteriskIdx < lastSeparatorIdx)
-            throw new RuntimeException("Could not parse classpath entry");
-
-        final int fileMaskFirstIdx = lastSeparatorIdx + 1;
-
-        final String fileMask =
-            (fileMaskFirstIdx >= clsPathEntry.length()) ? "*.jar" : 
clsPathEntry.substring(fileMaskFirstIdx);
-
-        Path path = Paths.get(lastSeparatorIdx > 0 ? clsPathEntry.substring(0, 
lastSeparatorIdx) : ".")
-            .toAbsolutePath()
-            .normalize();
-
-        if (lastSeparatorIdx == 0)
-            path = path.getRoot();
-
-        try {
-            DirectoryStream<Path> files =
-                Files.newDirectoryStream(path, fileMask);
-
-            for (Path f : files) {
-                String s = f.toString();
-
-                if (s.toLowerCase().endsWith(".jar"))
-                    clsPathContent.a(f.toString()).a(";");
-            }
-        }
-        catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    }
-
-    /**
-     * Prints the list of {@code *.jar} and {@code *.class} files containing 
in the classpath.
-     */
-    private void ackClassPathContent() {
-        assert log != null;
-
-        boolean enabled = 
IgniteSystemProperties.getBoolean(IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP,
-            DFLT_LOG_CLASSPATH_CONTENT_ON_STARTUP);
-
-        if (enabled) {
-            String clsPath = System.getProperty("java.class.path", ".");
-
-            String[] clsPathElements = clsPath.split(File.pathSeparator);
-
-            U.log(log, "Classpath value: " + clsPath);
-
-            SB clsPathContent = new SB("List of files containing in classpath: 
");
-
-            for (String clsPathEntry : clsPathElements) {
-                try {
-                    if (clsPathEntry.contains("*"))
-                        ackClassPathWildCard(clsPathEntry, clsPathContent);
-                    else
-                        ackClassPathEntry(clsPathEntry, clsPathContent);
-                }
-                catch (Exception e) {
-                    U.warn(log, String.format("Could not log class path entry 
'%s': %s", clsPathEntry, e.getMessage()));
-                }
-            }
-
-            U.log(log, clsPathContent.toString());
-        }
-    }
-
     /**
      * @param cfg Ignite configuration to use.
      * @param errHnd Error handler to use for notification about startup 
problems.
@@ -965,8 +847,7 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
         WorkersRegistry workerRegistry,
         Thread.UncaughtExceptionHandler hnd,
         TimeBag startTimer
-    )
-        throws IgniteCheckedException {
+    ) throws IgniteCheckedException {
         gw.compareAndSet(null, new 
GridKernalGatewayImpl(cfg.getIgniteInstanceName()));
 
         GridKernalGateway gw = this.gw.get();
@@ -1018,32 +899,7 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
 
         longJVMPauseDetector.start();
 
-        RuntimeMXBean rtBean = ManagementFactory.getRuntimeMXBean();
-
-        // Ack various information.
-        ackAsciiLogo();
-        ackConfigUrl();
-        ackConfiguration(cfg);
-        ackDaemon();
-        ackOsInfo();
-        ackLanguageRuntime();
-        ackRemoteManagement();
-        ackLogger();
-        ackVmArguments(rtBean);
-        ackClassPaths(rtBean);
-        ackSystemProperties();
-        ackEnvironmentVariables();
-        ackMemoryConfiguration();
-        ackCacheConfiguration();
-        ackP2pConfiguration();
-        ackRebalanceConfiguration();
-        ackIPv4StackFlagIsSet();
-        ackWaitForBackupsOnShutdownPropertyIsUsed();
-
-        // Ack 3-rd party licenses location.
-        if (log.isInfoEnabled() && cfg.getIgniteHome() != null)
-            log.info("3-rd party licenses can be found at: " + 
cfg.getIgniteHome() + File.separatorChar + "libs" +
-                File.separatorChar + "licenses");
+        info.ackKernalInited(log, cfg);
 
         // Check that user attributes are not conflicting
         // with internally reserved names.
@@ -1052,12 +908,6 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
                 throw new IgniteCheckedException("User attribute has illegal 
name: '" + name + "'. Note that all names " +
                     "starting with '" + ATTR_PREFIX + "' are reserved for 
internal use.");
 
-        // Ack local node user attributes.
-        logNodeUserAttributes();
-
-        // Ack configuration.
-        ackSpis();
-
         List<PluginProvider> plugins = cfg.getPluginProviders() != null && 
cfg.getPluginProviders().length > 0 ?
             Arrays.asList(cfg.getPluginProviders()) : U.allPluginProviders();
 
@@ -1156,8 +1006,6 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
             startManager(new GridCollisionManager(ctx));
             startManager(new GridIndexingManager(ctx));
 
-            ackSecurity();
-
             // Assign discovery manager to context before other processors 
start so they
             // are able to register custom event listener.
             GridDiscoveryManager discoMgr = new GridDiscoveryManager(ctx);
@@ -1494,34 +1342,23 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
             }, interval, interval);
         }
 
+        Ignite g = this;
         long metricsLogFreq = cfg.getMetricsLogFrequency();
 
         if (metricsLogFreq > 0) {
-            metricsLogTask = ctx.timeout().schedule(new Runnable() {
-                private final DecimalFormat dblFmt = doubleFormat();
-
-                @Override public void run() {
-                    ackNodeMetrics(
-                        dblFmt,
-                        ctx.pools().getExecutorService(),
-                        ctx.pools().getSystemExecutorService(),
-                        ctx.pools().getStripedExecutorService(),
-                        ctx.pools().customExecutors()
-                    );
+            metricsLogTask = ctx.timeout().schedule(() -> {
+                try {
+                    info.ackNodeBasicMetrics(log, g);
+                    info.ackNodeDataStorageMetrics(log, g);
+                    info.ackNodeMemoryStatisticsMetrics(log, g);
+                }
+                catch (IgniteClientDisconnectedException ignore) {
+                    // No-op.
                 }
             }, metricsLogFreq, metricsLogFreq);
         }
 
-        ctx.performance().add("Disable assertions (remove '-ea' from JVM 
options)", !U.assertionsEnabled());
-
-        ctx.performance().logSuggestions(log, igniteInstanceName);
-
-        U.quietAndInfo(log, "To start Console Management & Monitoring run 
ignitevisorcmd.{sh|bat}");
-
-        if 
(!IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_QUIET, true))
-            ackClassPathContent();
-
-        ackStart(rtBean);
+        info.ackKernalStarted(log, this);
 
         if (!isDaemon())
             
ctx.discovery().ackTopology(ctx.discovery().localJoin().joinTopologyVersion().topologyVersion(),
@@ -1530,11 +1367,6 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
         startTimer.finishGlobalStage("Await exchange");
     }
 
-    /** */
-    private static DecimalFormat doubleFormat() {
-        return new DecimalFormat("#.##", 
DecimalFormatSymbols.getInstance(Locale.US));
-    }
-
     /**
      * @return Ignite security processor. See {@link IgniteSecurity} for 
details.
      */
@@ -1801,7 +1633,7 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
         add(ATTR_SHUTDOWN_POLICY, cfg.getShutdownPolicy().index());
 
         add(ATTR_DEPLOYMENT_MODE, cfg.getDeploymentMode());
-        add(ATTR_LANG_RUNTIME, getLanguage());
+        add(ATTR_LANG_RUNTIME, U.language(U.resolveClassLoader(cfg)));
 
         add(ATTR_JVM_PID, U.jvmPid());
 
@@ -1956,510 +1788,9 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
         }
     }
 
-    /**
-     * @param helper Helper to attach to kernal context.
-     */
-    private void addHelper(Object helper) {
-        ctx.addHelper(helper);
-    }
-
-    /**
-     * Gets "on" or "off" string for given boolean value.
-     *
-     * @param b Boolean value to convert.
-     * @return Result string.
-     */
-    private String onOff(boolean b) {
-        return b ? "on" : "off";
-    }
-
-    /**
-     * @return {@code true} if the REST processor is enabled, {@code false} 
the otherwise.
-     */
-    private boolean isRestEnabled() {
-        assert cfg != null;
-
-        return cfg.getConnectorConfiguration() != null &&
-            // By default rest processor doesn't start on client nodes.
-            (!isClientNode() || (isClientNode() && 
IgniteSystemProperties.getBoolean(IGNITE_REST_START_ON_CLIENT)));
-    }
-
-    /**
-     * @return {@code True} if node client or daemon otherwise {@code false}.
-     */
-    private boolean isClientNode() {
-        return cfg.isClientMode() || cfg.isDaemon();
-    }
-
-    /**
-     * Acks remote management.
-     */
-    private void ackRemoteManagement() {
-        assert log != null;
-
-        if (!log.isInfoEnabled())
-            return;
-
-        SB sb = new SB();
-
-        sb.a("Remote Management [");
-
-        boolean on = isJmxRemoteEnabled();
-
-        sb.a("restart: ").a(onOff(isRestartEnabled())).a(", ");
-        sb.a("REST: ").a(onOff(isRestEnabled())).a(", ");
-        sb.a("JMX (");
-        sb.a("remote: ").a(onOff(on));
-
-        if (on) {
-            sb.a(", ");
-
-            sb.a("port: 
").a(System.getProperty("com.sun.management.jmxremote.port", "<n/a>")).a(", ");
-            sb.a("auth: 
").a(onOff(Boolean.getBoolean("com.sun.management.jmxremote.authenticate"))).a(",
 ");
-
-            // By default SSL is enabled, that's why additional check for null 
is needed.
-            // See 
http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html
-            sb.a("ssl: 
").a(onOff(Boolean.getBoolean("com.sun.management.jmxremote.ssl") ||
-                System.getProperty("com.sun.management.jmxremote.ssl") == 
null));
-        }
-
-        sb.a(")");
-
-        sb.a(']');
-
-        log.info(sb.toString());
-    }
-
-    /**
-     * Acks configuration URL.
-     */
-    private void ackConfigUrl() {
-        assert log != null;
-
-        if (log.isInfoEnabled())
-            log.info("Config URL: " + System.getProperty(IGNITE_CONFIG_URL, 
"n/a"));
-    }
-
-    /**
-     * @param cfg Ignite configuration to ack.
-     */
-    private void ackConfiguration(IgniteConfiguration cfg) {
-        assert log != null;
-
-        if (log.isInfoEnabled())
-            log.info(cfg.toString());
-    }
-
-    /**
-     * Acks Logger configuration.
-     */
-    private void ackLogger() {
-        assert log != null;
-
-        if (log.isInfoEnabled())
-            log.info("Logger: " + log.getLoggerInfo());
-    }
-
-    /**
-     * Acks ASCII-logo. Thanks to http://patorjk.com/software/taag
-     */
-    private void ackAsciiLogo() {
-        assert log != null;
-
-        if (System.getProperty(IGNITE_NO_ASCII) == null) {
-            String ver = "ver. " + ACK_VER_STR;
-
-            // Big thanks to: http://patorjk.com/software/taag
-            // Font name "Small Slant"
-            if (log.isInfoEnabled()) {
-                log.info(NL + NL +
-                    ">>>    __________  ________________  " + NL +
-                    ">>>   /  _/ ___/ |/ /  _/_  __/ __/  " + NL +
-                    ">>>  _/ // (7 7    // /  / / / _/    " + NL +
-                    ">>> /___/\\___/_/|_/___/ /_/ /___/   " + NL +
-                    ">>> " + NL +
-                    ">>> " + ver + NL +
-                    ">>> " + COPYRIGHT + NL +
-                    ">>> " + NL +
-                    ">>> Ignite documentation: " + "http://"; + SITE + NL
-                );
-            }
-
-            if (log.isQuiet()) {
-                U.quiet(false,
-                    "   __________  ________________ ",
-                    "  /  _/ ___/ |/ /  _/_  __/ __/ ",
-                    " _/ // (7 7    // /  / / / _/   ",
-                    "/___/\\___/_/|_/___/ /_/ /___/  ",
-                    "",
-                    ver,
-                    COPYRIGHT,
-                    "",
-                    "Ignite documentation: " + "http://"; + SITE,
-                    "",
-                    "Quiet mode.");
-
-                String fileName = log.fileName();
-
-                if (fileName != null)
-                    U.quiet(false, "  ^-- Logging to file '" + fileName + 
'\'');
-
-                U.quiet(false, "  ^-- Logging by '" + log.getLoggerInfo() + 
'\'');
-
-                U.quiet(false,
-                    "  ^-- To see **FULL** console log here add 
-DIGNITE_QUIET=false or \"-v\" to ignite.{sh|bat}",
-                    "");
-            }
-        }
-    }
-
-    /**
-     * Prints start info.
-     *
-     * @param rtBean Java runtime bean.
-     */
-    private void ackStart(RuntimeMXBean rtBean) {
-        ClusterNode locNode = localNode();
-
-        if (log.isQuiet()) {
-            U.quiet(false, "");
-
-            U.quiet(false, "Ignite node started OK (id=" + U.id8(locNode.id()) 
+
-                (F.isEmpty(igniteInstanceName) ? "" : ", instance name=" + 
igniteInstanceName) + ')');
-        }
-
-        if (log.isInfoEnabled()) {
-            String ack = "Ignite ver. " + VER_STR + '#' + BUILD_TSTAMP_STR + 
"-sha1:" + REV_HASH_STR;
-
-            String dash = U.dash(ack.length());
-
-            SB sb = new SB();
-
-            for (GridPortRecord rec : ctx.ports().records())
-                sb.a(rec.protocol()).a(":").a(rec.port()).a(" ");
-
-            String str =
-                NL + NL +
-                    ">>> " + dash + NL +
-                    ">>> " + ack + NL +
-                    ">>> " + dash + NL +
-                    ">>> OS name: " + U.osString() + NL +
-                    ">>> CPU(s): " + locNode.metrics().getTotalCpus() + NL +
-                    ">>> Heap: " + U.heapSize(locNode, 2) + "GB" + NL +
-                    ">>> VM name: " + rtBean.getName() + NL +
-                    (igniteInstanceName == null ? "" : ">>> Ignite instance 
name: " + igniteInstanceName + NL) +
-                    ">>> Local node [" +
-                    "ID=" + locNode.id().toString().toUpperCase() +
-                    ", order=" + locNode.order() + ", clientMode=" + 
ctx.clientNode() +
-                    "]" + NL +
-                    ">>> Local node addresses: " + 
U.addressesAsString(locNode) + NL +
-                    ">>> Local ports: " + sb + NL;
-
-            log.info(str);
-        }
-
-        if (ctx.state().clusterState().state() == ClusterState.INACTIVE) {
-            U.quietAndInfo(log, ">>> Ignite cluster is in INACTIVE state 
(limited functionality available). " +
-                "Use control.(sh|bat) script or 
IgniteCluster.state(ClusterState.ACTIVE) to change the state.");
-        }
-    }
-
-    /**
-     * Logs out OS information.
-     */
-    private void ackOsInfo() {
-        assert log != null;
-
-        if (log.isQuiet())
-            U.quiet(false, "OS: " + U.osString());
-
-        if (log.isInfoEnabled()) {
-            log.info("OS: " + U.osString());
-            log.info("OS user: " + System.getProperty("user.name"));
-
-            int jvmPid = U.jvmPid();
-
-            log.info("PID: " + (jvmPid == -1 ? "N/A" : jvmPid));
-        }
-    }
-
-    /**
-     * Logs out language runtime.
-     */
-    private void ackLanguageRuntime() {
-        assert log != null;
-
-        if (log.isQuiet())
-            U.quiet(false, "VM information: " + U.jdkString());
-
-        if (log.isInfoEnabled()) {
-            log.info("Language runtime: " + getLanguage());
-            log.info("VM information: " + U.jdkString());
-            log.info("VM total memory: " + U.heapSize(2) + "GB");
-        }
-    }
-
-    /**
-     * Logs out node metrics.
-     *
-     * @param dblFmt Decimal format.
-     * @param execSvc Executor service.
-     * @param sysExecSvc System executor service.
-     * @param customExecSvcs Custom named executors.
-     */
-    private void ackNodeMetrics(DecimalFormat dblFmt,
-        ExecutorService execSvc,
-        ExecutorService sysExecSvc,
-        ExecutorService stripedExecSvc,
-        Map<String, ? extends ExecutorService> customExecSvcs
-    ) {
-        if (!log.isInfoEnabled())
-            return;
-
-        try {
-            ClusterMetrics m = cluster().localNode().metrics();
-
-            int localCpus = m.getTotalCpus();
-            double cpuLoadPct = m.getCurrentCpuLoad() * 100;
-            double avgCpuLoadPct = m.getAverageCpuLoad() * 100;
-            double gcPct = m.getCurrentGcCpuLoad() * 100;
-
-            // Heap params.
-            long heapUsed = m.getHeapMemoryUsed();
-            long heapMax = m.getHeapMemoryMaximum();
-
-            long heapUsedInMBytes = heapUsed / MEGABYTE;
-            long heapCommInMBytes = m.getHeapMemoryCommitted() / MEGABYTE;
-
-            double freeHeapPct = heapMax > 0 ? ((double)((heapMax - heapUsed) 
* 100)) / heapMax : -1;
-
-            int hosts = 0;
-            int servers = 0;
-            int clients = 0;
-            int cpus = 0;
-
-            try {
-                ClusterMetrics metrics = cluster().metrics();
-
-                Collection<ClusterNode> nodes0 = cluster().nodes();
-
-                hosts = U.neighborhood(nodes0).size();
-                servers = cluster().forServers().nodes().size();
-                clients = cluster().forClients().nodes().size();
-                cpus = metrics.getTotalCpus();
-            }
-            catch (IgniteException ignore) {
-                // No-op.
-            }
-
-            String dataStorageInfo = 
dataStorageReport(ctx.cache().context().database(), dblFmt, true);
-
-            String id = U.id8(localNode().id());
-
-            AffinityTopologyVersion topVer = 
ctx.discovery().topologyVersionEx();
-
-            ClusterNode locNode = ctx.discovery().localNode();
-
-            String networkDetails = "";
-
-            if (!F.isEmpty(cfg.getLocalHost()))
-                networkDetails += ", localHost=" + cfg.getLocalHost();
-
-            if (locNode instanceof TcpDiscoveryNode)
-                networkDetails += ", discoPort=" + 
((TcpDiscoveryNode)locNode).discoveryPort();
-
-            if (cfg.getCommunicationSpi() instanceof TcpCommunicationSpi)
-                networkDetails += ", commPort=" + 
((TcpCommunicationSpi)cfg.getCommunicationSpi()).boundPort();
-
-            SB msg = new SB();
-
-            msg.nl()
-                .a("Metrics for local node (to disable set 
'metricsLogFrequency' to 0)").nl()
-                .a("    ^-- Node [id=").a(id).a(name() != null ? ", name=" + 
name() : "").a(", uptime=")
-                .a(upTimeFormatted()).a("]").nl()
-                .a("    ^-- Cluster [hosts=").a(hosts).a(", 
CPUs=").a(cpus).a(", servers=").a(servers)
-                .a(", clients=").a(clients).a(", 
topVer=").a(topVer.topologyVersion())
-                .a(", 
minorTopVer=").a(topVer.minorTopologyVersion()).a("]").nl()
-                .a("    ^-- Network 
[addrs=").a(locNode.addresses()).a(networkDetails).a("]").nl()
-                .a("    ^-- CPU [CPUs=").a(localCpus).a(", 
curLoad=").a(dblFmt.format(cpuLoadPct))
-                .a("%, avgLoad=").a(dblFmt.format(avgCpuLoadPct)).a("%, 
GC=").a(dblFmt.format(gcPct)).a("%]").nl()
-                .a("    ^-- Heap [used=").a(dblFmt.format(heapUsedInMBytes))
-                .a("MB, free=").a(dblFmt.format(freeHeapPct))
-                .a("%, comm=").a(dblFmt.format(heapCommInMBytes)).a("MB]").nl()
-                .a(dataStorageInfo)
-                .a("    ^-- Outbound messages queue 
[size=").a(m.getOutboundMessagesQueueSize()).a("]").nl()
-                .a("    ^-- ").a(createExecutorDescription("Public thread 
pool", execSvc)).nl()
-                .a("    ^-- ").a(createExecutorDescription("System thread 
pool", sysExecSvc)).nl()
-                .a("    ^-- ").a(createExecutorDescription("Striped thread 
pool", stripedExecSvc));
-
-            if (customExecSvcs != null) {
-                for (Map.Entry<String, ? extends ExecutorService> entry : 
customExecSvcs.entrySet())
-                    msg.nl().a("    ^-- 
").a(createExecutorDescription(entry.getKey(), entry.getValue()));
-            }
-
-            log.info(msg.toString());
-
-            ctx.cache().context().database().dumpStatistics(log);
-        }
-        catch (IgniteClientDisconnectedException ignore) {
-            // No-op.
-        }
-    }
-
     /** */
-    public static String dataStorageReport(IgniteCacheDatabaseSharedManager 
db, boolean includeMemoryStatistics) {
-        return dataStorageReport(db, doubleFormat(), includeMemoryStatistics);
-    }
-
-    /** */
-    private static String dataStorageReport(IgniteCacheDatabaseSharedManager 
db, DecimalFormat dblFmt,
-        boolean includeMemoryStatistics) {
-        // Off-heap params.
-        Collection<DataRegion> regions = db.dataRegions();
-
-        SB dataRegionsInfo = new SB();
-
-        long loadedPages = 0;
-        long offHeapUsedSummary = 0;
-        long offHeapMaxSummary = 0;
-        long offHeapCommSummary = 0;
-        long pdsUsedSummary = 0;
-
-        boolean persistenceEnabled = false;
-
-        if (!F.isEmpty(regions)) {
-            for (DataRegion region : regions) {
-                DataRegionConfiguration regCfg = region.config();
-
-                long pagesCnt = region.pageMemory().loadedPages();
-
-                long offHeapUsed = region.pageMemory().systemPageSize() * 
pagesCnt;
-                long offHeapInit = regCfg.getInitialSize();
-                long offHeapMax = regCfg.getMaxSize();
-                long offHeapComm = region.metrics().getOffHeapSize();
-
-                long offHeapUsedInMBytes = offHeapUsed / MEGABYTE;
-                long offHeapMaxInMBytes = offHeapMax / MEGABYTE;
-                long offHeapCommInMBytes = offHeapComm / MEGABYTE;
-                long offHeapInitInMBytes = offHeapInit / MEGABYTE;
-
-                double freeOffHeapPct = offHeapMax > 0 ?
-                    ((double)((offHeapMax - offHeapUsed) * 100)) / offHeapMax 
: -1;
-
-                offHeapUsedSummary += offHeapUsed;
-                offHeapMaxSummary += offHeapMax;
-                offHeapCommSummary += offHeapComm;
-                loadedPages += pagesCnt;
-
-                String type = "user";
-
-                try {
-                    if (region == db.dataRegion(null))
-                        type = "default";
-                    else if 
(INTERNAL_DATA_REGION_NAMES.contains(regCfg.getName()))
-                        type = "internal";
-                }
-                catch (IgniteCheckedException ice) {
-                    // Should never happen
-                    ice.printStackTrace();
-                }
-
-                dataRegionsInfo.a("    ^--   ")
-                    .a(regCfg.getName()).a(" region [type=").a(type)
-                    .a(", persistence=").a(regCfg.isPersistenceEnabled())
-                    .a(", 
lazyAlloc=").a(regCfg.isLazyMemoryAllocation()).a(',').nl()
-                    .a("      ...  ")
-                    .a("initCfg=").a(dblFmt.format(offHeapInitInMBytes))
-                    .a("MB, maxCfg=").a(dblFmt.format(offHeapMaxInMBytes))
-                    .a("MB, usedRam=").a(dblFmt.format(offHeapUsedInMBytes))
-                    .a("MB, freeRam=").a(dblFmt.format(freeOffHeapPct))
-                    .a("%, 
allocRam=").a(dblFmt.format(offHeapCommInMBytes)).a("MB");
-
-                if (regCfg.isPersistenceEnabled()) {
-                    long pdsUsed = region.metrics().getTotalAllocatedSize();
-                    long pdsUsedInMBytes = pdsUsed / MEGABYTE;
-
-                    pdsUsedSummary += pdsUsed;
-
-                    dataRegionsInfo.a(", 
allocTotal=").a(dblFmt.format(pdsUsedInMBytes)).a("MB");
-
-                    persistenceEnabled = true;
-                }
-
-                dataRegionsInfo.a(']').nl();
-            }
-        }
-
-        SB info = new SB();
-
-        if (includeMemoryStatistics) {
-            long offHeapUsedInMBytes = offHeapUsedSummary / MEGABYTE;
-            long offHeapCommInMBytes = offHeapCommSummary / MEGABYTE;
-
-            double freeOffHeapPct = offHeapMaxSummary > 0 ?
-                ((double)((offHeapMaxSummary - offHeapUsedSummary) * 100)) / 
offHeapMaxSummary : -1;
-
-            info.a("    ^-- Off-heap memory 
[used=").a(dblFmt.format(offHeapUsedInMBytes))
-                .a("MB, free=").a(dblFmt.format(freeOffHeapPct))
-                .a("%, 
allocated=").a(dblFmt.format(offHeapCommInMBytes)).a("MB]").nl()
-                .a("    ^-- Page memory [pages=").a(loadedPages).a("]").nl();
-        }
-
-        info.a(dataRegionsInfo);
-
-        if (persistenceEnabled) {
-            long pdsUsedMBytes = pdsUsedSummary / MEGABYTE;
-
-            info.a("    ^-- Ignite persistence 
[used=").a(dblFmt.format(pdsUsedMBytes)).a("MB]").nl();
-        }
-
-        return info.toString();
-    }
-
-    /**
-     * @return Language runtime.
-     */
-    private String getLanguage() {
-        boolean scala = false;
-        boolean groovy = false;
-        boolean clojure = false;
-
-        for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
-            String s = elem.getClassName().toLowerCase();
-
-            if (s.contains("scala")) {
-                scala = true;
-
-                break;
-            }
-            else if (s.contains("groovy")) {
-                groovy = true;
-
-                break;
-            }
-            else if (s.contains("clojure")) {
-                clojure = true;
-
-                break;
-            }
-        }
-
-        if (scala) {
-            try (InputStream in = 
getClass().getResourceAsStream("/library.properties")) {
-                Properties props = new Properties();
-
-                if (in != null)
-                    props.load(in);
-
-                return "Scala ver. " + props.getProperty("version.number", 
"<unknown>");
-            }
-            catch (Exception ignore) {
-                return "Scala ver. <unknown>";
-            }
-        }
-
-        // How to get Groovy and Clojure version at runtime?!?
-        return groovy ? "Groovy" : clojure ? "Clojure" : U.jdkName() + " ver. 
" + U.jdkVersion();
+    public void dataStorageReport() {
+        info.ackNodeDataStorageMetrics(log, this);
     }
 
     /**
@@ -2630,52 +1961,7 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
                 gw.writeUnlock();
             }
 
-            // Ack stop.
-            if (log.isQuiet()) {
-                String nodeName = igniteInstanceName == null ? "" : "name=" + 
igniteInstanceName + ", ";
-
-                if (!errOnStop)
-                    U.quiet(false, "Ignite node stopped OK [" + nodeName + 
"uptime=" +
-                        X.timeSpan2DHMSM(U.currentTimeMillis() - startTime) + 
']');
-                else
-                    U.quiet(true, "Ignite node stopped wih ERRORS [" + 
nodeName + "uptime=" +
-                        X.timeSpan2DHMSM(U.currentTimeMillis() - startTime) + 
']');
-            }
-
-            if (log.isInfoEnabled())
-                if (!errOnStop) {
-                    String ack = "Ignite ver. " + VER_STR + '#' + 
BUILD_TSTAMP_STR + "-sha1:" + REV_HASH_STR +
-                        " stopped OK";
-
-                    String dash = U.dash(ack.length());
-
-                    log.info(NL + NL +
-                        ">>> " + dash + NL +
-                        ">>> " + ack + NL +
-                        ">>> " + dash + NL +
-                        (igniteInstanceName == null ? "" : ">>> Ignite 
instance name: " + igniteInstanceName + NL) +
-                        ">>> Grid uptime: " + 
X.timeSpan2DHMSM(U.currentTimeMillis() - startTime) +
-                        NL +
-                        NL);
-                }
-                else {
-                    String ack = "Ignite ver. " + VER_STR + '#' + 
BUILD_TSTAMP_STR + "-sha1:" + REV_HASH_STR +
-                        " stopped with ERRORS";
-
-                    String dash = U.dash(ack.length());
-
-                    log.info(NL + NL +
-                        ">>> " + ack + NL +
-                        ">>> " + dash + NL +
-                        (igniteInstanceName == null ? "" : ">>> Ignite 
instance name: " + igniteInstanceName + NL) +
-                        ">>> Grid uptime: " + 
X.timeSpan2DHMSM(U.currentTimeMillis() - startTime) +
-                        NL +
-                        ">>> See log above for detailed error message." + NL +
-                        ">>> Note that some errors during stop can prevent 
grid from" + NL +
-                        ">>> maintaining correct topology since this node may 
have" + NL +
-                        ">>> not exited grid properly." + NL +
-                        NL);
-                }
+            info.ackKernalStopped(log, this, errOnStop);
 
             try {
                 U.onGridStop();
@@ -2721,49 +2007,6 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
         return ctx;
     }
 
-    /**
-     * Prints all system properties in debug mode.
-     */
-    private void ackSystemProperties() {
-        assert log != null;
-
-        if (log.isDebugEnabled() && S.includeSensitive())
-            for (Map.Entry<Object, Object> entry : 
IgniteSystemProperties.snapshot().entrySet())
-                log.debug("System property [" + entry.getKey() + '=' + 
entry.getValue() + ']');
-    }
-
-    /**
-     * Prints all user attributes in info mode.
-     */
-    private void logNodeUserAttributes() {
-        assert log != null;
-
-        if (log.isInfoEnabled())
-            for (Map.Entry<?, ?> attr : cfg.getUserAttributes().entrySet())
-                log.info("Local node user attribute [" + attr.getKey() + '=' + 
attr.getValue() + ']');
-    }
-
-    /**
-     * Prints all environment variables in debug mode.
-     */
-    private void ackEnvironmentVariables() {
-        assert log != null;
-
-        if (log.isDebugEnabled())
-            for (Map.Entry<?, ?> envVar : System.getenv().entrySet())
-                log.debug("Environment variable [" + envVar.getKey() + '=' + 
envVar.getValue() + ']');
-    }
-
-    /**
-     * Acks daemon mode status.
-     */
-    private void ackDaemon() {
-        assert log != null;
-
-        if (log.isInfoEnabled())
-            log.info("Daemon mode: " + (isDaemon() ? "on" : "off"));
-    }
-
     /**
      * @return {@code True} is this node is daemon.
      */
@@ -2780,7 +2023,7 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
      * @return {@code True} if remote JMX management is enabled - {@code 
false} otherwise.
      */
     @Override public boolean isJmxRemoteEnabled() {
-        return System.getProperty("com.sun.management.jmxremote") != null;
+        return U.isJmxRemoteEnabled();
     }
 
     /**
@@ -2792,210 +2035,7 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
      * @see Ignition#restart(boolean)
      */
     @Override public boolean isRestartEnabled() {
-        return System.getProperty(IGNITE_SUCCESS_FILE) != null;
-    }
-
-    /**
-     * Prints all configuration properties in info mode and SPIs in debug mode.
-     */
-    private void ackSpis() {
-        assert log != null;
-
-        if (log.isDebugEnabled()) {
-            log.debug("+-------------+");
-            log.debug("START SPI LIST:");
-            log.debug("+-------------+");
-            log.debug("Grid checkpoint SPI     : " + 
Arrays.toString(cfg.getCheckpointSpi()));
-            log.debug("Grid collision SPI      : " + cfg.getCollisionSpi());
-            log.debug("Grid communication SPI  : " + 
cfg.getCommunicationSpi());
-            log.debug("Grid deployment SPI     : " + cfg.getDeploymentSpi());
-            log.debug("Grid discovery SPI      : " + cfg.getDiscoverySpi());
-            log.debug("Grid event storage SPI  : " + cfg.getEventStorageSpi());
-            log.debug("Grid failover SPI       : " + 
Arrays.toString(cfg.getFailoverSpi()));
-            log.debug("Grid load balancing SPI : " + 
Arrays.toString(cfg.getLoadBalancingSpi()));
-        }
-    }
-
-    /**
-     * Acknowledge that the rebalance configuration properties are setted 
correctly.
-     *
-     * @throws IgniteCheckedException If rebalance configuration validation 
fail.
-     */
-    private void ackRebalanceConfiguration() throws IgniteCheckedException {
-        if (cfg.isClientMode()) {
-            if (cfg.getRebalanceThreadPoolSize() != 
IgniteConfiguration.DFLT_REBALANCE_THREAD_POOL_SIZE)
-                U.warn(log, "Setting the rebalance pool size has no effect on 
the client mode");
-        }
-        else {
-            if (cfg.getRebalanceThreadPoolSize() < 1)
-                throw new IgniteCheckedException("Rebalance thread pool size 
minimal allowed value is 1. " +
-                    "Change IgniteConfiguration.rebalanceThreadPoolSize 
property before next start.");
-
-            if (cfg.getRebalanceBatchesPrefetchCount() < 1)
-                throw new IgniteCheckedException("Rebalance batches prefetch 
count minimal allowed value is 1. " +
-                    "Change IgniteConfiguration.rebalanceBatchesPrefetchCount 
property before next start.");
-
-            if (cfg.getRebalanceBatchSize() <= 0)
-                throw new IgniteCheckedException("Rebalance batch size must be 
greater than zero. " +
-                    "Change IgniteConfiguration.rebalanceBatchSize property 
before next start.");
-
-            if (cfg.getRebalanceThrottle() < 0)
-                throw new IgniteCheckedException("Rebalance throttle can't 
have negative value. " +
-                    "Change IgniteConfiguration.rebalanceThrottle property 
before next start.");
-
-            if (cfg.getRebalanceTimeout() < 0)
-                throw new IgniteCheckedException("Rebalance message timeout 
can't have negative value. " +
-                    "Change IgniteConfiguration.rebalanceTimeout property 
before next start.");
-
-            for (CacheConfiguration ccfg : cfg.getCacheConfiguration()) {
-                if (ccfg.getRebalanceBatchesPrefetchCount() < 1)
-                    throw new IgniteCheckedException("Rebalance batches 
prefetch count minimal allowed value is 1. " +
-                        "Change 
CacheConfiguration.rebalanceBatchesPrefetchCount property before next start. " +
-                        "[cache=" + ccfg.getName() + "]");
-            }
-        }
-    }
-
-    /**
-     * Acknowledge the Ignite configuration related to the data storage.
-     */
-    private void ackMemoryConfiguration() {
-        DataStorageConfiguration memCfg = cfg.getDataStorageConfiguration();
-
-        if (memCfg == null)
-            return;
-
-        U.log(log, "System cache's DataRegion size is configured to " +
-            (memCfg.getSystemDataRegionConfiguration().getInitialSize() / 
(1024 * 1024)) + " MB. " +
-            "Use DataStorageConfiguration.systemRegionInitialSize property to 
change the setting.");
-    }
-
-    /**
-     * Acknowledge all caches configurations presented in the 
IgniteConfiguration.
-     */
-    private void ackCacheConfiguration() {
-        CacheConfiguration[] cacheCfgs = cfg.getCacheConfiguration();
-
-        if (cacheCfgs == null || cacheCfgs.length == 0)
-            U.warn(log, "Cache is not configured - in-memory data grid is 
off.");
-        else {
-            SB sb = new SB();
-
-            HashMap<String, ArrayList<String>> memPlcNamesMapping = new 
HashMap<>();
-
-            for (CacheConfiguration c : cacheCfgs) {
-                String cacheName = U.maskName(c.getName());
-
-                String memPlcName = c.getDataRegionName();
-
-                if (CU.isSystemCache(cacheName))
-                    memPlcName = "sysMemPlc";
-                else if (memPlcName == null && 
cfg.getDataStorageConfiguration() != null)
-                    memPlcName = 
cfg.getDataStorageConfiguration().getDefaultDataRegionConfiguration().getName();
-
-                if (!memPlcNamesMapping.containsKey(memPlcName))
-                    memPlcNamesMapping.put(memPlcName, new 
ArrayList<String>());
-
-                ArrayList<String> cacheNames = 
memPlcNamesMapping.get(memPlcName);
-
-                cacheNames.add(cacheName);
-            }
-
-            for (Map.Entry<String, ArrayList<String>> e : 
memPlcNamesMapping.entrySet()) {
-                sb.a("in '").a(e.getKey()).a("' dataRegion: [");
-
-                for (String s : e.getValue())
-                    sb.a("'").a(s).a("', ");
-
-                sb.d(sb.length() - 2, sb.length()).a("], ");
-            }
-
-            U.log(log, "Configured caches [" + sb.d(sb.length() - 2, 
sb.length()).toString() + ']');
-        }
-    }
-
-    /**
-     * Acknowledge configuration related to the peer class loading.
-     */
-    private void ackP2pConfiguration() {
-        assert cfg != null;
-
-        if (cfg.isPeerClassLoadingEnabled())
-            U.warn(
-                log,
-                "Peer class loading is enabled (disable it in production for 
performance and " +
-                    "deployment consistency reasons)");
-    }
-
-    /**
-     * Prints security status.
-     */
-    private void ackSecurity() {
-        assert log != null;
-
-        U.quietAndInfo(log, "Security status [authentication=" + 
onOff(ctx.security().enabled())
-            + ", sandbox=" + onOff(ctx.security().sandbox().enabled())
-            + ", tls/ssl=" + onOff(ctx.config().getSslContextFactory() != 
null) + ']');
-    }
-
-    /**
-     * Prints out VM arguments and IGNITE_HOME in info mode.
-     *
-     * @param rtBean Java runtime bean.
-     */
-    private void ackVmArguments(RuntimeMXBean rtBean) {
-        assert log != null;
-
-        // Ack IGNITE_HOME and VM arguments.
-        if (log.isInfoEnabled() && S.includeSensitive()) {
-            log.info("IGNITE_HOME=" + cfg.getIgniteHome());
-            log.info("VM arguments: " + rtBean.getInputArguments());
-        }
-    }
-
-    /**
-     * Prints out class paths in debug mode.
-     *
-     * @param rtBean Java runtime bean.
-     */
-    private void ackClassPaths(RuntimeMXBean rtBean) {
-        assert log != null;
-
-        // Ack all class paths.
-        if (log.isDebugEnabled()) {
-            try {
-                log.debug("Boot class path: " + rtBean.getBootClassPath());
-                log.debug("Class path: " + rtBean.getClassPath());
-                log.debug("Library path: " + rtBean.getLibraryPath());
-            }
-            catch (Exception ignore) {
-                // No-op: ignore for Java 9+ and non-standard JVMs.
-            }
-        }
-    }
-
-    /**
-     * Prints warning if 'java.net.preferIPv4Stack=true' is not set.
-     */
-    private void ackIPv4StackFlagIsSet() {
-        boolean preferIPv4 = 
Boolean.valueOf(System.getProperty("java.net.preferIPv4Stack"));
-
-        if (!preferIPv4) {
-            assert log != null;
-
-            U.quietAndWarn(log, "Please set system property 
'-Djava.net.preferIPv4Stack=true' " +
-                "to avoid possible problems in mixed environments.");
-        }
-    }
-
-    /**
-     * Prints warning if IGNITE_WAIT_FOR_BACKUPS_ON_SHUTDOWN is used.
-     */
-    private void ackWaitForBackupsOnShutdownPropertyIsUsed() {
-        if 
(IgniteSystemProperties.getString(IgniteSystemProperties.IGNITE_WAIT_FOR_BACKUPS_ON_SHUTDOWN)
 != null) {
-            log.warning("IGNITE_WAIT_FOR_BACKUPS_ON_SHUTDOWN system property 
is deprecated and will be removed " +
-                "in a future version. Use ShutdownPolicy instead.");
-        }
+        return U.isRestartEnabled();
     }
 
     /**
@@ -4330,6 +3370,20 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
         }
     }
 
+    /**
+     * @return Loaded info provider.
+     */
+    private static IgniteLogInfoProvider loadInfoProvider() {
+        try {
+            return 
ofNullable(F.first(U.loadService(IgniteLogInfoProvider.class))).orElse(new 
IgniteLogInfoProviderImpl());
+        }
+        catch (Throwable t) {
+            U.error(null, t.getMessage());
+        }
+
+        return new IgniteLogInfoProviderImpl();
+    }
+
     /**
      * @param cls Component interface.
      * @return Name of component implementation class for open source edition.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java 
b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
index 1c263a4ee57..20ad0f234bb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
@@ -141,7 +141,6 @@ import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_LOCAL_HOST;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_NO_SHUTDOWN_HOOK;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_OVERRIDE_CONSISTENT_ID;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_RESTART_CODE;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_SUCCESS_FILE;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT;
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -475,7 +474,7 @@ public class IgnitionEx {
      * @see Ignition#RESTART_EXIT_CODE
      */
     public static void restart(boolean cancel) {
-        String file = System.getProperty(IGNITE_SUCCESS_FILE);
+        String file = U.IGNITE_SUCCESS_FILE_PROPERTY;
 
         if (file == null)
             U.warn(null, "Cannot restart node when restart not enabled.");
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/plugin/IgniteLogInfoProvider.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/plugin/IgniteLogInfoProvider.java
new file mode 100644
index 00000000000..6d74eaad08e
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/plugin/IgniteLogInfoProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.plugin;
+
+import java.util.ServiceLoader;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.configuration.IgniteConfiguration;
+
+/**
+ * Pluggable Ignite component that is responsible for printing custom 
information during the Ignite lifecycle start phase.
+ * The Ignite info is loaded using JDK {@link ServiceLoader}.
+ */
+public interface IgniteLogInfoProvider {
+    /**
+     * @param log Ignite logger.
+     * @param cfg Ignite configuration.
+     */
+    public void ackKernalInited(IgniteLogger log, IgniteConfiguration cfg);
+
+    /**
+     * @param log Ignite logger.
+     * @param ignite Ignite instance.
+     */
+    public void ackKernalStarted(IgniteLogger log, Ignite ignite);
+
+    /**
+     * @param log Ignite logger.
+     * @param ignite Ignite instance.
+     * @param err {@code True} if error occurred during the Ignite instance 
stop process.
+     */
+    public void ackKernalStopped(IgniteLogger log, Ignite ignite, boolean err);
+
+    /**
+     * @param log Ignite logger.
+     * @param ignite Ignite instance.
+     */
+    public void ackNodeBasicMetrics(IgniteLogger log, Ignite ignite);
+
+    /**
+     * @param log Ignite logger.
+     * @param ignite Ignite instance.
+     */
+    public void ackNodeDataStorageMetrics(IgniteLogger log, Ignite ignite);
+
+    /**
+     * @param log Ignite logger.
+     * @param ignite Ignite instance.
+     */
+    public void ackNodeMemoryStatisticsMetrics(IgniteLogger log, Ignite 
ignite);
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/plugin/IgniteLogInfoProviderImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/plugin/IgniteLogInfoProviderImpl.java
new file mode 100644
index 00000000000..27fed709e3b
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/plugin/IgniteLogInfoProviderImpl.java
@@ -0,0 +1,1018 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.plugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.cluster.ClusterMetrics;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.cluster.ClusterState;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.GridLoggerProxy;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.persistence.DataRegion;
+import 
org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.port.GridPortRecord;
+import org.apache.ignite.internal.util.StripedExecutor;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.SB;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_CONFIG_URL;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_DAEMON;
+import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_NO_ASCII;
+import static 
org.apache.ignite.internal.IgniteKernal.DFLT_LOG_CLASSPATH_CONTENT_ON_STARTUP;
+import static org.apache.ignite.internal.IgniteKernal.NL;
+import static org.apache.ignite.internal.IgniteKernal.SITE;
+import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
+import static org.apache.ignite.internal.IgniteVersionUtils.BUILD_TSTAMP_STR;
+import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
+import static org.apache.ignite.internal.IgniteVersionUtils.REV_HASH_STR;
+import static org.apache.ignite.internal.IgniteVersionUtils.VER_STR;
+import static 
org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager.INTERNAL_DATA_REGION_NAMES;
+import static org.apache.ignite.internal.util.IgniteUtils.MB;
+
+/**
+ * Default implementation of Ignite information.
+ */
+public class IgniteLogInfoProviderImpl implements IgniteLogInfoProvider {
+    /** Format of output metrics. */
+    private final DecimalFormat decimalFormat = new DecimalFormat("#.##", 
DecimalFormatSymbols.getInstance(Locale.US));
+
+    /** {@inheritDoc} */
+    @Override public void ackKernalInited(IgniteLogger log, 
IgniteConfiguration cfg) {
+        assert log != null;
+
+        RuntimeMXBean rtBean = ManagementFactory.getRuntimeMXBean();
+
+        ackAsciiLogo(log, cfg, rtBean);
+        ackConfigUrl(log);
+        ackConfiguration(log, cfg);
+        ackDaemon(log, cfg);
+        ackOsInfo(log);
+        ackLanguageRuntime(log, cfg);
+        ackRemoteManagement(log, cfg);
+        ackLogger(log);
+        ackVmArguments(log, cfg, rtBean);
+        ackClassPaths(log, rtBean);
+        ackSystemProperties(log);
+        ackEnvironmentVariables(log);
+        ackMemoryConfiguration(log, cfg);
+        ackCacheConfiguration(log, cfg);
+
+        if (cfg.isPeerClassLoadingEnabled())
+            ackP2pConfiguration(log);
+
+        ackRebalanceConfiguration(log, cfg);
+        ackIPv4StackFlagIsSet(log);
+        ackWaitForBackupsOnShutdownPropertyIsUsed(log);
+        ack3rdPartyLicenses(log, cfg);
+        logNodeUserAttributes(log, cfg);
+        ackSpis(log, cfg);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void ackNodeBasicMetrics(IgniteLogger log, Ignite ignite) 
{
+        ackNodeBasicMetrics(log, (IgniteEx)ignite, decimalFormat);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void ackNodeDataStorageMetrics(IgniteLogger log, Ignite 
ignite) {
+        GridKernalContext ctx = ((IgniteEx)ignite).context();
+
+        dataStorageReport(log, ctx.cache().context().database(), 
decimalFormat);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void ackNodeMemoryStatisticsMetrics(IgniteLogger log, 
Ignite ignite) {
+        GridKernalContext ctx = ((IgniteEx)ignite).context();
+
+        memoryStatisticsReport(log, ctx.cache().context().database(), 
decimalFormat);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void ackKernalStarted(IgniteLogger log, Ignite ignite) {
+        IgniteEx igEx = (IgniteEx)ignite;
+
+        ackSecurity(log, ignite);
+        ackPerformanceSuggestions(log, igEx);
+        ackVisorConsole(log);
+        ackClassPathContent(log);
+        ackNodeInfo(log, igEx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void ackKernalStopped(IgniteLogger log, Ignite ignite, 
boolean err) {
+        ackNodeStopped(log, (IgniteEx)ignite, err);
+    }
+
+    /**
+     * Acks ASCII-logo. Thanks to http://patorjk.com/software/taag
+     */
+    void ackAsciiLogo(IgniteLogger log, IgniteConfiguration cfg, RuntimeMXBean 
rtBean) {
+        if (System.getProperty(IGNITE_NO_ASCII) != null)
+            return;
+
+        String ver = "ver. " + ACK_VER_STR;
+
+        // Big thanks to: http://patorjk.com/software/taag
+        // Font name "Small Slant"
+        if (log.isInfoEnabled()) {
+            log.info(NL + NL +
+                ">>>    __________  ________________  " + NL +
+                ">>>   /  _/ ___/ |/ /  _/_  __/ __/  " + NL +
+                ">>>  _/ // (7 7    // /  / / / _/    " + NL +
+                ">>> /___/\\___/_/|_/___/ /_/ /___/   " + NL +
+                ">>> " + NL +
+                ">>> " + ver + NL +
+                ">>> " + COPYRIGHT + NL +
+                ">>> " + NL +
+                ">>> Ignite documentation: " + "https://"; + SITE + NL
+            );
+        }
+
+        if (log.isQuiet()) {
+            U.quiet(false,
+                "   __________  ________________ ",
+                "  /  _/ ___/ |/ /  _/_  __/ __/ ",
+                " _/ // (7 7    // /  / / / _/   ",
+                "/___/\\___/_/|_/___/ /_/ /x___/  ",
+                "",
+                ver,
+                COPYRIGHT,
+                "",
+                "Ignite documentation: " + "https://"; + SITE,
+                "",
+                "Quiet mode.");
+
+            String fileName = log.fileName();
+
+            if (fileName != null)
+                U.quiet(false, "  ^-- Logging to file '" + fileName + '\'');
+
+            U.quiet(false, "  ^-- Logging by '" + 
((GridLoggerProxy)log).getLoggerInfo() + '\'');
+
+            U.quiet(false,
+                "  ^-- To see **FULL** console log here add 
-DIGNITE_QUIET=false or \"-v\" to ignite.{sh|bat}",
+                "");
+        }
+    }
+
+    /**
+     * Acks configuration URL.
+     */
+    void ackConfigUrl(IgniteLogger log) {
+        if (log.isInfoEnabled())
+            log.info("Config URL: " + System.getProperty(IGNITE_CONFIG_URL, 
"n/a"));
+    }
+
+    /**
+     * @param cfg Ignite configuration to ack.
+     */
+    void ackConfiguration(IgniteLogger log, IgniteConfiguration cfg) {
+        if (log.isInfoEnabled())
+            log.info(cfg.toString());
+    }
+
+    /**
+     * Acks daemon mode status.
+     */
+    void ackDaemon(IgniteLogger log, IgniteConfiguration cfg) {
+        if (log.isInfoEnabled())
+            log.info("Daemon mode: " + onOff(cfg.isDaemon() || 
IgniteSystemProperties.getBoolean(IGNITE_DAEMON)));
+    }
+
+    /**
+     * Logs out OS information.
+     */
+    void ackOsInfo(IgniteLogger log) {
+        if (log.isQuiet())
+            U.quiet(false, "OS: " + U.osString());
+
+        if (log.isInfoEnabled()) {
+            log.info("OS: " + U.osString());
+            log.info("OS user: " + System.getProperty("user.name"));
+
+            int jvmPid = U.jvmPid();
+
+            log.info("PID: " + (jvmPid == -1 ? "N/A" : jvmPid));
+        }
+    }
+
+    /**
+     * Logs out language runtime.
+     */
+    void ackLanguageRuntime(IgniteLogger log, IgniteConfiguration cfg) {
+        if (log.isQuiet())
+            U.quiet(false, "VM information: " + U.jdkString());
+
+        if (log.isInfoEnabled()) {
+            log.info("Language runtime: " + 
U.language(U.resolveClassLoader(cfg)));
+            log.info("VM information: " + U.jdkString());
+            log.info("VM total memory: " + U.heapSize(2) + "GB");
+        }
+    }
+
+    /**
+     * Acks remote management.
+     */
+    void ackRemoteManagement(IgniteLogger log, IgniteConfiguration cfg) {
+        if (!log.isInfoEnabled())
+            return;
+
+        SB sb = new SB();
+
+        sb.a("Remote Management [");
+
+        boolean on = U.isJmxRemoteEnabled();
+
+        sb.a("restart: ").a(onOff(U.isRestartEnabled())).a(", ");
+        sb.a("REST: ").a(onOff(U.isRestEnabled(cfg))).a(", ");
+        sb.a("JMX (");
+        sb.a("remote: ").a(onOff(on));
+
+        if (on) {
+            sb.a(", ");
+
+            sb.a("port: 
").a(System.getProperty("com.sun.management.jmxremote.port", "<n/a>")).a(", ");
+            sb.a("auth: 
").a(onOff(Boolean.getBoolean("com.sun.management.jmxremote.authenticate"))).a(",
 ");
+
+            // By default, SSL is enabled, that's why additional check for 
null is needed.
+            // See 
http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html
+            sb.a("ssl: 
").a(onOff(Boolean.getBoolean("com.sun.management.jmxremote.ssl") ||
+                System.getProperty("com.sun.management.jmxremote.ssl") == 
null));
+        }
+
+        sb.a(")");
+
+        sb.a(']');
+
+        log.info(sb.toString());
+    }
+
+    /**
+     * Acks Logger configuration.
+     */
+    void ackLogger(IgniteLogger log) {
+        if (log.isInfoEnabled())
+            log.info("Logger: " + ((GridLoggerProxy)log).getLoggerInfo());
+    }
+
+    /**
+     * Prints out VM arguments and IGNITE_HOME in info mode.
+     *
+     * @param rtBean Java runtime bean.
+     */
+    void ackVmArguments(IgniteLogger log, IgniteConfiguration cfg, 
RuntimeMXBean rtBean) {
+        // Ack IGNITE_HOME and VM arguments.
+        if (log.isInfoEnabled() && S.includeSensitive()) {
+            log.info("IGNITE_HOME=" + cfg.getIgniteHome());
+            log.info("VM arguments: " + rtBean.getInputArguments());
+        }
+    }
+
+    /**
+     * Prints out class paths in debug mode.
+     *
+     * @param rtBean Java runtime bean.
+     */
+    void ackClassPaths(IgniteLogger log, RuntimeMXBean rtBean) {
+        // Ack all class paths.
+        if (log.isDebugEnabled()) {
+            try {
+                log.debug("Boot class path: " + rtBean.getBootClassPath());
+                log.debug("Class path: " + rtBean.getClassPath());
+                log.debug("Library path: " + rtBean.getLibraryPath());
+            }
+            catch (Exception ignore) {
+                // No-op: ignore for Java 9+ and non-standard JVMs.
+            }
+        }
+    }
+
+    /**
+     * Prints all system properties in debug mode.
+     */
+    void ackSystemProperties(IgniteLogger log) {
+        if (log.isDebugEnabled() && S.includeSensitive())
+            for (Map.Entry<Object, Object> entry : 
IgniteSystemProperties.snapshot().entrySet())
+                log.debug("System property [" + entry.getKey() + '=' + 
entry.getValue() + ']');
+    }
+
+    /**
+     * Prints all environment variables in debug mode.
+     */
+    void ackEnvironmentVariables(IgniteLogger log) {
+        if (log.isDebugEnabled())
+            for (Map.Entry<?, ?> envVar : System.getenv().entrySet())
+                log.debug("Environment variable [" + envVar.getKey() + '=' + 
envVar.getValue() + ']');
+    }
+
+    /**
+     * Acknowledge the Ignite configuration related to the data storage.
+     */
+    void ackMemoryConfiguration(IgniteLogger log, IgniteConfiguration cfg) {
+        DataStorageConfiguration memCfg = cfg.getDataStorageConfiguration();
+
+        if (memCfg == null)
+            return;
+
+        U.log(log, "System cache's DataRegion size is configured to " +
+            (memCfg.getSystemDataRegionConfiguration().getInitialSize() / 
(1024 * 1024)) + " MB. " +
+            "Use DataStorageConfiguration.systemRegionInitialSize property to 
change the setting.");
+    }
+
+    /**
+     * Acknowledge all caches configurations presented in the 
IgniteConfiguration.
+     */
+    void ackCacheConfiguration(IgniteLogger log, IgniteConfiguration cfg) {
+        CacheConfiguration[] cacheCfgs = cfg.getCacheConfiguration();
+
+        if (cacheCfgs == null || cacheCfgs.length == 0)
+            U.warn(log, "Cache is not configured - in-memory data grid is 
off.");
+        else {
+            SB sb = new SB();
+
+            HashMap<String, ArrayList<String>> memPlcNamesMapping = new 
HashMap<>();
+
+            for (CacheConfiguration c : cacheCfgs) {
+                String cacheName = U.maskName(c.getName());
+
+                String memPlcName = c.getDataRegionName();
+
+                if (CU.isSystemCache(cacheName))
+                    memPlcName = "sysMemPlc";
+                else if (memPlcName == null && 
cfg.getDataStorageConfiguration() != null)
+                    memPlcName = 
cfg.getDataStorageConfiguration().getDefaultDataRegionConfiguration().getName();
+
+                if (!memPlcNamesMapping.containsKey(memPlcName))
+                    memPlcNamesMapping.put(memPlcName, new 
ArrayList<String>());
+
+                ArrayList<String> cacheNames = 
memPlcNamesMapping.get(memPlcName);
+
+                cacheNames.add(cacheName);
+            }
+
+            for (Map.Entry<String, ArrayList<String>> e : 
memPlcNamesMapping.entrySet()) {
+                sb.a("in '").a(e.getKey()).a("' dataRegion: [");
+
+                for (String s : e.getValue())
+                    sb.a("'").a(s).a("', ");
+
+                sb.d(sb.length() - 2, sb.length()).a("], ");
+            }
+
+            U.log(log, "Configured caches [" + sb.d(sb.length() - 2, 
sb.length()).toString() + ']');
+        }
+    }
+
+    /**
+     * Acknowledge configuration related to the peer class loading.
+     */
+    void ackP2pConfiguration(IgniteLogger log) {
+        U.warn(log,
+            "Peer class loading is enabled (disable it in production for 
performance and " +
+                "deployment consistency reasons)");
+    }
+
+    /**
+     * Acknowledge that the rebalance configuration properties are setted 
correctly.
+     */
+    void ackRebalanceConfiguration(IgniteLogger log, IgniteConfiguration cfg) {
+        if (cfg.isClientMode()) {
+            if (cfg.getRebalanceThreadPoolSize() != 
IgniteConfiguration.DFLT_REBALANCE_THREAD_POOL_SIZE)
+                U.warn(log, "Setting the rebalance pool size has no effect on 
the client mode");
+        }
+        else {
+            if (cfg.getRebalanceThreadPoolSize() < 1)
+                throw new IgniteException("Rebalance thread pool size minimal 
allowed value is 1. " +
+                    "Change IgniteConfiguration.rebalanceThreadPoolSize 
property before next start.");
+
+            if (cfg.getRebalanceBatchesPrefetchCount() < 1)
+                throw new IgniteException("Rebalance batches prefetch count 
minimal allowed value is 1. " +
+                    "Change IgniteConfiguration.rebalanceBatchesPrefetchCount 
property before next start.");
+
+            if (cfg.getRebalanceBatchSize() <= 0)
+                throw new IgniteException("Rebalance batch size must be 
greater than zero. " +
+                    "Change IgniteConfiguration.rebalanceBatchSize property 
before next start.");
+
+            if (cfg.getRebalanceThrottle() < 0)
+                throw new IgniteException("Rebalance throttle can't have 
negative value. " +
+                    "Change IgniteConfiguration.rebalanceThrottle property 
before next start.");
+
+            if (cfg.getRebalanceTimeout() < 0)
+                throw new IgniteException("Rebalance message timeout can't 
have negative value. " +
+                    "Change IgniteConfiguration.rebalanceTimeout property 
before next start.");
+
+            for (CacheConfiguration ccfg : cfg.getCacheConfiguration()) {
+                if (ccfg.getRebalanceBatchesPrefetchCount() < 1)
+                    throw new IgniteException("Rebalance batches prefetch 
count minimal allowed value is 1. " +
+                        "Change 
CacheConfiguration.rebalanceBatchesPrefetchCount property before next start. " +
+                        "[cache=" + ccfg.getName() + "]");
+            }
+        }
+    }
+
+    /**
+     * Prints warning if 'java.net.preferIPv4Stack=true' is not set.
+     */
+    void ackIPv4StackFlagIsSet(IgniteLogger log) {
+        boolean preferIPv4 = 
Boolean.parseBoolean(System.getProperty("java.net.preferIPv4Stack"));
+
+        if (!preferIPv4) {
+            U.quietAndWarn(log, "Please set system property 
'-Djava.net.preferIPv4Stack=true' " +
+                "to avoid possible problems in mixed environments.");
+        }
+    }
+
+    /**
+     * Prints warning if IGNITE_WAIT_FOR_BACKUPS_ON_SHUTDOWN is used.
+     */
+    void ackWaitForBackupsOnShutdownPropertyIsUsed(IgniteLogger log) {
+        if 
(IgniteSystemProperties.getString(IgniteSystemProperties.IGNITE_WAIT_FOR_BACKUPS_ON_SHUTDOWN)
 == null)
+            return;
+
+        log.warning("IGNITE_WAIT_FOR_BACKUPS_ON_SHUTDOWN system property is 
deprecated and will be removed " +
+            "in a future version. Use ShutdownPolicy instead.");
+    }
+
+    /**
+     * Print 3-rd party licenses location.
+     */
+    void ack3rdPartyLicenses(IgniteLogger log, IgniteConfiguration cfg) {
+        // Ack 3-rd party licenses location.
+        if (log.isInfoEnabled() && cfg.getIgniteHome() != null)
+            log.info("3-rd party licenses can be found at: " + 
cfg.getIgniteHome() + File.separatorChar + "libs" +
+                File.separatorChar + "licenses");
+    }
+
+    /**
+     * Prints all user attributes in info mode.
+     */
+    void logNodeUserAttributes(IgniteLogger log, IgniteConfiguration cfg) {
+        if (log.isInfoEnabled())
+            for (Map.Entry<?, ?> attr : cfg.getUserAttributes().entrySet())
+                log.info("Local node user attribute [" + attr.getKey() + '=' + 
attr.getValue() + ']');
+    }
+
+    /**
+     * Prints all configuration properties in info mode and SPIs in debug mode.
+     */
+    void ackSpis(IgniteLogger log, IgniteConfiguration cfg) {
+        if (log.isDebugEnabled()) {
+            log.debug("+-------------+");
+            log.debug("START SPI LIST:");
+            log.debug("+-------------+");
+            log.debug("Grid checkpoint SPI       : " + 
Arrays.toString(cfg.getCheckpointSpi()));
+            log.debug("Grid collision SPI        : " + cfg.getCollisionSpi());
+            log.debug("Grid communication SPI    : " + 
cfg.getCommunicationSpi());
+            log.debug("Grid deployment SPI       : " + cfg.getDeploymentSpi());
+            log.debug("Grid discovery SPI        : " + cfg.getDiscoverySpi());
+            log.debug("Grid event storage SPI    : " + 
cfg.getEventStorageSpi());
+            log.debug("Grid failover SPI         : " + 
Arrays.toString(cfg.getFailoverSpi()));
+            log.debug("Grid load balancing SPI   : " + 
Arrays.toString(cfg.getLoadBalancingSpi()));
+            log.debug("Grid Metrics Exporter SPI : " + 
Arrays.toString(cfg.getMetricExporterSpi()));
+        }
+    }
+
+    /**
+     * Print performance suggestions.
+     */
+    void ackPerformanceSuggestions(IgniteLogger log, IgniteEx ignite) {
+        GridKernalContext ctx = ignite.context();
+
+        ctx.performance().add("Disable assertions (remove '-ea' from JVM 
options)", !U.assertionsEnabled());
+        ctx.performance().logSuggestions(log, ignite.name());
+    }
+
+    /**
+     * Print info about visor commandline console.
+     */
+    void ackVisorConsole(IgniteLogger log) {
+        U.quietAndInfo(log, "To start Console Management & Monitoring run 
ignitevisorcmd.{sh|bat}");
+    }
+
+    /**
+     * Prints the list of {@code *.jar} and {@code *.class} files containing 
in the classpath.
+     */
+    void ackClassPathContent(IgniteLogger log) {
+        if 
(IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_QUIET, true))
+            return;
+
+        boolean enabled = 
IgniteSystemProperties.getBoolean(IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP,
+            DFLT_LOG_CLASSPATH_CONTENT_ON_STARTUP);
+
+        if (enabled) {
+            String clsPath = System.getProperty("java.class.path", ".");
+
+            String[] clsPathElements = clsPath.split(File.pathSeparator);
+
+            U.log(log, "Classpath value: " + clsPath);
+
+            SB clsPathContent = new SB("List of files containing in classpath: 
");
+
+            for (String clsPathEntry : clsPathElements) {
+                try {
+                    if (clsPathEntry.contains("*"))
+                        ackClassPathWildCard(clsPathEntry, clsPathContent);
+                    else
+                        ackClassPathEntry(clsPathEntry, clsPathContent);
+                }
+                catch (Exception e) {
+                    U.warn(log, String.format("Could not log class path entry 
'%s': %s", clsPathEntry, e.getMessage()));
+                }
+            }
+
+            U.log(log, clsPathContent.toString());
+        }
+    }
+
+    /**
+     * @param clsPathEntry Classpath string to process.
+     * @param clsPathContent StringBuilder to attach path to.
+     */
+    void ackClassPathWildCard(String clsPathEntry, SB clsPathContent) {
+        final int lastSeparatorIdx = clsPathEntry.lastIndexOf(File.separator);
+
+        final int asteriskIdx = clsPathEntry.indexOf('*');
+
+        // Just to log possibly incorrect entries to err.
+        if (asteriskIdx >= 0 && asteriskIdx < lastSeparatorIdx)
+            throw new RuntimeException("Could not parse classpath entry");
+
+        final int fileMaskFirstIdx = lastSeparatorIdx + 1;
+
+        final String fileMask =
+            (fileMaskFirstIdx >= clsPathEntry.length()) ? "*.jar" : 
clsPathEntry.substring(fileMaskFirstIdx);
+
+        Path path = Paths.get(lastSeparatorIdx > 0 ? clsPathEntry.substring(0, 
lastSeparatorIdx) : ".")
+            .toAbsolutePath()
+            .normalize();
+
+        if (lastSeparatorIdx == 0)
+            path = path.getRoot();
+
+        try {
+            DirectoryStream<Path> files =
+                Files.newDirectoryStream(path, fileMask);
+
+            for (Path f : files) {
+                String s = f.toString();
+
+                if (s.toLowerCase().endsWith(".jar"))
+                    clsPathContent.a(f.toString()).a(";");
+            }
+        }
+        catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    /**
+     * @param clsPathEntry Classpath string to process.
+     * @param clsPathContent StringBuilder to attach path to.
+     */
+    void ackClassPathEntry(String clsPathEntry, SB clsPathContent) {
+        File clsPathElementFile = new File(clsPathEntry);
+
+        if (clsPathElementFile.isDirectory())
+            clsPathContent.a(clsPathEntry).a(";");
+        else {
+            String extension = clsPathEntry.length() >= 4
+                ? clsPathEntry.substring(clsPathEntry.length() - 
4).toLowerCase()
+                : null;
+
+            if (".jar".equals(extension) || ".zip".equals(extension))
+                clsPathContent.a(clsPathEntry).a(";");
+        }
+    }
+
+    /**
+     * Print local node information after kernal startup.
+     */
+    void ackNodeInfo(IgniteLogger log, IgniteEx ignite) {
+        ClusterNode locNode = ignite.localNode();
+        GridKernalContext ctx = ignite.context();
+
+        if (log.isQuiet()) {
+            U.quiet(false, "");
+
+            U.quiet(false, "Ignite node started OK (id=" + U.id8(locNode.id()) 
+
+                (F.isEmpty(ignite.name()) ? "" : ", instance name=" + 
ignite.name()) + ')');
+        }
+
+        if (log.isInfoEnabled()) {
+            String ack = "Ignite ver. " + VER_STR + '#' + BUILD_TSTAMP_STR + 
"-sha1:" + REV_HASH_STR;
+
+            String dash = U.dash(ack.length());
+
+            SB sb = new SB();
+
+            for (GridPortRecord rec : ctx.ports().records())
+                sb.a(rec.protocol()).a(":").a(rec.port()).a(" ");
+
+            String str =
+                NL + NL +
+                    ">>> " + dash + NL +
+                    ">>> " + ack + NL +
+                    ">>> " + dash + NL +
+                    ">>> OS name: " + U.osString() + NL +
+                    ">>> CPU(s): " + locNode.metrics().getTotalCpus() + NL +
+                    ">>> Heap: " + U.heapSize(locNode, 2) + "GB" + NL +
+                    ">>> VM name: " + ((IgniteKernal)ignite).vmName() + NL +
+                    (ignite.name() == null ? "" : ">>> Ignite instance name: " 
+ ignite.name() + NL) +
+                    ">>> Local node [" +
+                    "ID=" + locNode.id().toString().toUpperCase() +
+                    ", order=" + locNode.order() + ", clientMode=" + 
ctx.clientNode() +
+                    "]" + NL +
+                    ">>> Local node addresses: " + 
U.addressesAsString(locNode) + NL +
+                    ">>> Local ports: " + sb + NL +
+                    ">>> " + dash + NL;
+
+            log.info(str);
+        }
+
+        if (ctx.state().clusterState().state() == ClusterState.INACTIVE) {
+            U.quietAndInfo(log, ">>> Ignite cluster is in INACTIVE state 
(limited functionality available). " +
+                "Use control.(sh|bat) script or 
IgniteCluster.state(ClusterState.ACTIVE) to change the state.");
+        }
+    }
+
+    /**
+     * Logs out node metrics.
+     */
+    void ackNodeBasicMetrics(IgniteLogger log, IgniteEx ignite, DecimalFormat 
dblFmt) {
+        if (!log.isInfoEnabled())
+            return;
+
+        GridKernalContext ctx = ignite.context();
+        IgniteConfiguration cfg = ignite.configuration();
+
+        ExecutorService execSvc = ctx.pools().getExecutorService();
+        ExecutorService sysExecSvc = ctx.pools().getSystemExecutorService();
+        ExecutorService stripedExecSvc = 
ctx.pools().getStripedExecutorService();
+        Map<String, ? extends ExecutorService> customExecSvcs = 
ctx.pools().customExecutors();
+
+        ClusterMetrics m = ignite.cluster().localNode().metrics();
+
+        int localCpus = m.getTotalCpus();
+        double cpuLoadPct = m.getCurrentCpuLoad() * 100;
+        double avgCpuLoadPct = m.getAverageCpuLoad() * 100;
+        double gcPct = m.getCurrentGcCpuLoad() * 100;
+
+        // Heap params.
+        long heapUsed = m.getHeapMemoryUsed();
+        long heapMax = m.getHeapMemoryMaximum();
+
+        long heapUsedInMBytes = heapUsed / MB;
+        long heapCommInMBytes = m.getHeapMemoryCommitted() / MB;
+
+        double freeHeapPct = heapMax > 0 ? ((double)((heapMax - heapUsed) * 
100)) / heapMax : -1;
+
+        int hosts = 0;
+        int servers = 0;
+        int clients = 0;
+        int cpus = 0;
+
+        try {
+            ClusterMetrics metrics = ignite.cluster().metrics();
+
+            Collection<ClusterNode> nodes0 = ignite.cluster().nodes();
+
+            hosts = U.neighborhood(nodes0).size();
+            servers = ignite.cluster().forServers().nodes().size();
+            clients = ignite.cluster().forClients().nodes().size();
+            cpus = metrics.getTotalCpus();
+        }
+        catch (IgniteException ignore) {
+            // No-op.
+        }
+
+        String id = U.id8(ignite.localNode().id());
+
+        AffinityTopologyVersion topVer = ctx.discovery().topologyVersionEx();
+
+        ClusterNode locNode = ctx.discovery().localNode();
+
+        String networkDetails = "";
+
+        if (!F.isEmpty(cfg.getLocalHost()))
+            networkDetails += ", localHost=" + cfg.getLocalHost();
+
+        if (locNode instanceof TcpDiscoveryNode)
+            networkDetails += ", discoPort=" + 
((TcpDiscoveryNode)locNode).discoveryPort();
+
+        if (cfg.getCommunicationSpi() instanceof TcpCommunicationSpi)
+            networkDetails += ", commPort=" + 
((TcpCommunicationSpi)cfg.getCommunicationSpi()).boundPort();
+
+        SB msg = new SB();
+
+        msg.nl()
+            .a("Metrics for local node (to disable set 'metricsLogFrequency' 
to 0)").nl()
+            .a("    ^-- Node [id=").a(id).a(ignite.name() != null ? ", name=" 
+ ignite.name() : "").a(", uptime=")
+            .a(((IgniteKernal)ignite).upTimeFormatted()).a("]").nl()
+            .a("    ^-- Cluster [hosts=").a(hosts).a(", CPUs=").a(cpus).a(", 
servers=").a(servers)
+            .a(", clients=").a(clients).a(", 
topVer=").a(topVer.topologyVersion())
+            .a(", minorTopVer=").a(topVer.minorTopologyVersion()).a("]").nl()
+            .a("    ^-- Network 
[addrs=").a(locNode.addresses()).a(networkDetails).a("]").nl()
+            .a("    ^-- CPU [CPUs=").a(localCpus).a(", 
curLoad=").a(dblFmt.format(cpuLoadPct))
+            .a("%, avgLoad=").a(dblFmt.format(avgCpuLoadPct)).a("%, 
GC=").a(dblFmt.format(gcPct)).a("%]").nl()
+            .a("    ^-- Heap [used=").a(dblFmt.format(heapUsedInMBytes))
+            .a("MB, free=").a(dblFmt.format(freeHeapPct))
+            .a("%, comm=").a(dblFmt.format(heapCommInMBytes)).a("MB]").nl()
+            .a("    ^-- Outbound messages queue 
[size=").a(m.getOutboundMessagesQueueSize()).a("]").nl()
+            .a("    ^-- ").a(createExecutorDescription("Public thread pool", 
execSvc)).nl()
+            .a("    ^-- ").a(createExecutorDescription("System thread pool", 
sysExecSvc)).nl()
+            .a("    ^-- ").a(createExecutorDescription("Striped thread pool", 
stripedExecSvc));
+
+        if (customExecSvcs != null) {
+            for (Map.Entry<String, ? extends ExecutorService> entry : 
customExecSvcs.entrySet())
+                msg.nl().a("    ^-- 
").a(createExecutorDescription(entry.getKey(), entry.getValue()));
+        }
+
+        log.info(msg.toString());
+
+        ctx.cache().context().database().dumpStatistics(log);
+    }
+
+    /**
+     * Create description of an executor service for logging.
+     *
+     * @param execSvcName Name of the service.
+     * @param execSvc Service to create a description for.
+     */
+    String createExecutorDescription(String execSvcName, ExecutorService 
execSvc) {
+        int poolSize = 0;
+        int poolActiveThreads = 0;
+        int poolQSize = 0;
+
+        if (execSvc instanceof ThreadPoolExecutor) {
+            ThreadPoolExecutor exec = (ThreadPoolExecutor)execSvc;
+
+            poolSize = exec.getPoolSize();
+            poolActiveThreads = Math.min(poolSize, exec.getActiveCount());
+            poolQSize = exec.getQueue().size();
+        }
+        else if (execSvc instanceof StripedExecutor) {
+            StripedExecutor exec = (StripedExecutor)execSvc;
+
+            poolSize = exec.stripesCount();
+            poolActiveThreads = exec.activeStripesCount();
+            poolQSize = exec.queueSize();
+        }
+
+        int poolIdleThreads = poolSize - poolActiveThreads;
+
+        return execSvcName + " [active=" + poolActiveThreads + ", idle=" + 
poolIdleThreads + ", qSize=" + poolQSize + "]";
+    }
+
+    /**
+     * Print data storage statistics.
+     */
+    void dataStorageReport(IgniteLogger log, IgniteCacheDatabaseSharedManager 
db, DecimalFormat dblFmt) {
+        if (F.isEmpty(db.dataRegions()))
+            return;
+
+        SB dataRegionsInfo = new SB();
+        dataRegionsInfo.nl();
+
+        for (DataRegion region : db.dataRegions()) {
+            DataRegionConfiguration regCfg = region.config();
+
+            long pagesCnt = region.pageMemory().loadedPages();
+
+            long offHeapUsed = region.pageMemory().systemPageSize() * pagesCnt;
+            long offHeapInit = regCfg.getInitialSize();
+            long offHeapMax = regCfg.getMaxSize();
+            long offHeapComm = region.metrics().getOffHeapSize();
+
+            long offHeapUsedInMBytes = offHeapUsed / MB;
+            long offHeapMaxInMBytes = offHeapMax / MB;
+            long offHeapCommInMBytes = offHeapComm / MB;
+            long offHeapInitInMBytes = offHeapInit / MB;
+
+            double freeOffHeapPct = offHeapMax > 0 ?
+                ((double)((offHeapMax - offHeapUsed) * 100)) / offHeapMax : -1;
+
+            String type = "user";
+
+            try {
+                if (region == db.dataRegion(null))
+                    type = "default";
+                else if (INTERNAL_DATA_REGION_NAMES.contains(regCfg.getName()))
+                    type = "internal";
+            }
+            catch (IgniteCheckedException ice) {
+                // Should never happen
+                ice.printStackTrace();
+            }
+
+            dataRegionsInfo.a("    ^--   ")
+                .a(regCfg.getName()).a(" region [type=").a(type)
+                .a(", persistence=").a(regCfg.isPersistenceEnabled())
+                .a(", 
lazyAlloc=").a(regCfg.isLazyMemoryAllocation()).a(',').nl()
+                .a("      ...  ")
+                .a("initCfg=").a(dblFmt.format(offHeapInitInMBytes))
+                .a("MB, maxCfg=").a(dblFmt.format(offHeapMaxInMBytes))
+                .a("MB, usedRam=").a(dblFmt.format(offHeapUsedInMBytes))
+                .a("MB, freeRam=").a(dblFmt.format(freeOffHeapPct))
+                .a("%, 
allocRam=").a(dblFmt.format(offHeapCommInMBytes)).a("MB");
+
+            if (regCfg.isPersistenceEnabled()) {
+                dataRegionsInfo.a(", allocTotal=")
+                    .a(dblFmt.format(region.metrics().getTotalAllocatedSize() 
/ MB)).a("MB");
+            }
+
+            dataRegionsInfo.a(']').nl();
+        }
+
+        if (log.isQuiet())
+            U.quietMultipleLines(false, dataRegionsInfo.toString());
+        else if (log.isInfoEnabled())
+            log.info(dataRegionsInfo.toString());
+    }
+
+    /**
+     * @param log Ignite Logger.
+     * @param db Database Shared Manager.
+     * @param dblFmt Double format.
+     */
+    void memoryStatisticsReport(IgniteLogger log, 
IgniteCacheDatabaseSharedManager db, DecimalFormat dblFmt) {
+        if (F.isEmpty(db.dataRegions()))
+            return;
+
+        SB sb = new SB();
+        sb.nl();
+
+        long loadedPages = 0;
+        long offHeapUsedSummary = 0;
+        long offHeapMaxSummary = 0;
+        long offHeapCommSummary = 0;
+        long pdsUsedSummary = 0;
+        boolean persistenceEnabled = false;
+
+        for (DataRegion region : db.dataRegions()) {
+            DataRegionConfiguration regCfg = region.config();
+
+            long pagesCnt = region.pageMemory().loadedPages();
+
+            long offHeapUsed = region.pageMemory().systemPageSize() * pagesCnt;
+            long offHeapMax = regCfg.getMaxSize();
+            long offHeapComm = region.metrics().getOffHeapSize();
+
+            offHeapUsedSummary += offHeapUsed;
+            offHeapMaxSummary += offHeapMax;
+            offHeapCommSummary += offHeapComm;
+            loadedPages += pagesCnt;
+
+            if (regCfg.isPersistenceEnabled()) {
+                pdsUsedSummary += region.metrics().getTotalAllocatedSize();
+
+                persistenceEnabled = true;
+            }
+        }
+
+        double freeOffHeapPct = offHeapMaxSummary > 0 ?
+            ((double)((offHeapMaxSummary - offHeapUsedSummary) * 100)) / 
offHeapMaxSummary : -1;
+
+        sb.nl()
+            .a("Data storage metrics for local node (to disable set 
'metricsLogFrequency' to 0)").nl()
+            .a("    ^-- Off-heap memory 
[used=").a(dblFmt.format(offHeapUsedSummary / MB))
+            .a("MB, free=").a(dblFmt.format(freeOffHeapPct))
+            .a("%, allocated=").a(dblFmt.format(offHeapCommSummary / 
MB)).a("MB]").nl()
+            .a("    ^-- Page memory [pages=").a(loadedPages).a("]").nl();
+
+        if (persistenceEnabled)
+            sb.a("    ^-- Ignite persistence 
[used=").a(dblFmt.format(pdsUsedSummary / MB)).a("MB]").nl();
+
+        if (log.isQuiet())
+            U.quietMultipleLines(false, sb.toString());
+        else if (log.isInfoEnabled())
+            log.info(sb.toString());
+    }
+
+    /** */
+    void ackNodeStopped(IgniteLogger log, IgniteEx ignite, boolean err) {
+        String igniteInstanceName = ignite.name();
+
+        // Ack stop.
+        if (log.isQuiet()) {
+            String nodeName = igniteInstanceName == null ? "" : "name=" + 
igniteInstanceName + ", ";
+
+            if (!err)
+                U.quiet(false, "Ignite node stopped OK [" + nodeName + 
"uptime=" +
+                    ((IgniteKernal)ignite).upTimeFormatted() + ']');
+            else
+                U.quiet(true, "Ignite node stopped wih ERRORS [" + nodeName + 
"uptime=" +
+                    ((IgniteKernal)ignite).upTimeFormatted() + ']');
+        }
+
+        if (!log.isInfoEnabled())
+            return;
+
+        if (!err) {
+            String ack = "Ignite ver. " + VER_STR + '#' + BUILD_TSTAMP_STR + 
"-sha1:" + REV_HASH_STR +
+                " stopped OK";
+
+            String dash = U.dash(ack.length());
+
+            log.info(NL + NL +
+                ">>> " + dash + NL +
+                ">>> " + ack + NL +
+                ">>> " + dash + NL +
+                (igniteInstanceName == null ? "" : ">>> Ignite instance name: 
" + igniteInstanceName + NL) +
+                ">>> Grid uptime: " + ((IgniteKernal)ignite).upTimeFormatted() 
+
+                NL +
+                NL);
+        }
+        else {
+            String ack = "Ignite ver. " + VER_STR + '#' + BUILD_TSTAMP_STR + 
"-sha1:" + REV_HASH_STR +
+                " stopped with ERRORS";
+
+            String dash = U.dash(ack.length());
+
+            log.info(NL + NL +
+                ">>> " + ack + NL +
+                ">>> " + dash + NL +
+                (igniteInstanceName == null ? "" : ">>> Ignite instance name: 
" + igniteInstanceName + NL) +
+                ">>> Grid uptime: " + ((IgniteKernal)ignite).upTimeFormatted() 
+
+                NL +
+                ">>> See log above for detailed error message." + NL +
+                ">>> Note that some errors during stop can prevent grid from" 
+ NL +
+                ">>> maintaining correct topology since this node may have" + 
NL +
+                ">>> not exited grid properly." + NL +
+                NL);
+        }
+    }
+
+    /**
+     * Prints security status.
+     */
+    void ackSecurity(IgniteLogger log, Ignite ignite) {
+        assert log != null;
+
+        GridKernalContext ctx = ((IgniteEx)ignite).context();
+
+        U.quietAndInfo(log, "Security status [authentication=" + 
onOff(ctx.security().enabled())
+            + ", sandbox=" + onOff(ctx.security().sandbox().enabled())
+            + ", tls/ssl=" + onOff(ctx.config().getSslContextFactory() != 
null) + ']');
+    }
+
+    /**
+     * Gets "on" or "off" string for given boolean value.
+     *
+     * @param b Boolean value to convert.
+     * @return Result string.
+     */
+    public static String onOff(boolean b) {
+        return b ? "on" : "off";
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
index 7caaf200a6d..d25458bf116 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
@@ -1551,16 +1551,9 @@ public class IgniteCacheDatabaseSharedManager extends 
GridCacheSharedManagerAdap
 
         dataRegionsStarted = true;
 
-        if (log.isQuiet()) {
-            U.quiet(false, "Data Regions Started: " + dataRegionMap.size());
+        U.quietAndInfo(log, "Data Regions Started: " + dataRegionMap.size());
 
-            U.quietMultipleLines(false, IgniteKernal.dataStorageReport(this, 
false));
-        }
-        else if (log.isInfoEnabled()) {
-            log.info("Data Regions Started: " + dataRegionMap.size());
-
-            log.info(IgniteKernal.dataStorageReport(this, false));
-        }
+        ((IgniteKernal)cctx.kernalContext().grid()).dataStorageReport();
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java 
b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index 1dfb16975f6..a525ea924df 100755
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -120,6 +120,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Properties;
 import java.util.Random;
 import java.util.ServiceLoader;
 import java.util.Set;
@@ -293,8 +294,10 @@ import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_LOCAL_HOST;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_MBEAN_APPEND_CLASS_LOADER_ID;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_MBEAN_APPEND_JVM_ID;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_NO_DISCO_ORDER;
+import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_REST_START_ON_CLIENT;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SSH_HOST;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SSH_USER_NAME;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SUCCESS_FILE;
 import static org.apache.ignite.IgniteSystemProperties.getBoolean;
 import static org.apache.ignite.events.EventType.EVTS_ALL;
 import static org.apache.ignite.events.EventType.EVTS_ALL_MINUS_METRIC_UPDATE;
@@ -644,6 +647,19 @@ public abstract class IgniteUtils {
     /** Byte count prefixes. */
     private static final String BYTE_CNT_PREFIXES = " KMGTPE";
 
+    /**
+     * Success file name property. This file is used with auto-restarting 
functionality when Ignite
+     * is started by supplied ignite.{bat|sh} scripts.
+     */
+    public static final String IGNITE_SUCCESS_FILE_PROPERTY = 
System.getProperty(IGNITE_SUCCESS_FILE);
+
+    /**
+     * JMX remote system property. Setting this property registered the Java 
VM platform's MBeans and published
+     * the Remote Method Invocation (RMI) connector via a private interface to 
allow JMX client applications
+     * to monitor a local Java platform, that is, a Java VM running on the 
same machine as the JMX client.
+     */
+    public static final String IGNITE_JMX_REMOTE_PROPERTY = 
System.getProperty("com.sun.management.jmxremote");
+
     /*
      * Initializes enterprise check.
      */
@@ -1044,16 +1060,25 @@ public abstract class IgniteUtils {
      * @return Plugins.
      */
     public static List<PluginProvider> allPluginProviders() {
-        return AccessController.doPrivileged(new 
PrivilegedAction<List<PluginProvider>>() {
-            @Override public List<PluginProvider> run() {
-                List<PluginProvider> providers = new ArrayList<>();
+        List<PluginProvider> providers = new ArrayList<>();
 
-                ServiceLoader<PluginProvider> ldr = 
ServiceLoader.load(PluginProvider.class);
+        Iterable<PluginProvider> it = loadService(PluginProvider.class);
 
-                for (PluginProvider provider : ldr)
-                    providers.add(provider);
+        for (PluginProvider provider : it)
+            providers.add(provider);
 
-                return providers;
+        return providers;
+    }
+
+    /**
+     * @param svcCls Service class to load.
+     * @param <S> Type of loaded interfaces.
+     * @return Lazy iterable structure over loaded class implementations.
+     */
+    public static <S> Iterable<S> loadService(Class<S> svcCls) {
+        return AccessController.doPrivileged(new 
PrivilegedAction<Iterable<S>>() {
+            @Override public Iterable<S> run() {
+                return ServiceLoader.load(svcCls);
             }
         });
     }
@@ -12316,4 +12341,75 @@ public abstract class IgniteUtils {
             }
         }
     }
+
+    /**
+     * @return Language runtime.
+     */
+    public static String language(ClassLoader ldr) {
+        boolean scala = false;
+        boolean groovy = false;
+        boolean clojure = false;
+
+        for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
+            String s = elem.getClassName().toLowerCase();
+
+            if (s.contains("scala")) {
+                scala = true;
+
+                break;
+            }
+            else if (s.contains("groovy")) {
+                groovy = true;
+
+                break;
+            }
+            else if (s.contains("clojure")) {
+                clojure = true;
+
+                break;
+            }
+        }
+
+        if (scala) {
+            try (InputStream in = 
ldr.getResourceAsStream("/library.properties")) {
+                Properties props = new Properties();
+
+                if (in != null)
+                    props.load(in);
+
+                return "Scala ver. " + props.getProperty("version.number", 
"<unknown>");
+            }
+            catch (Exception ignore) {
+                return "Scala ver. <unknown>";
+            }
+        }
+
+        // How to get Groovy and Clojure version at runtime?!?
+        return groovy ? "Groovy" : clojure ? "Clojure" : U.jdkName() + " ver. 
" + U.jdkVersion();
+    }
+
+    /**
+     * @return {@code True} if remote JMX management is enabled - {@code 
false} otherwise.
+     */
+    public static boolean isJmxRemoteEnabled() {
+        return IGNITE_JMX_REMOTE_PROPERTY != null;
+    }
+
+    /**
+     * @return {@code true} if the REST processor is enabled, {@code false} 
the otherwise.
+     */
+    public static boolean isRestEnabled(IgniteConfiguration cfg) {
+        boolean isClientNode = cfg.isClientMode() || cfg.isDaemon();
+
+        // By default, rest processor doesn't start on client nodes.
+        return cfg.getConnectorConfiguration() != null &&
+            (!isClientNode || (isClientNode && 
IgniteSystemProperties.getBoolean(IGNITE_REST_START_ON_CLIENT)));
+    }
+
+    /**
+     * @return {@code True} if restart mode is enabled, {@code false} 
otherwise.
+     */
+    public static boolean isRestartEnabled() {
+        return IGNITE_SUCCESS_FILE_PROPERTY != null;
+    }
 }
diff --git 
a/modules/core/src/test/java/org/apache/ignite/thread/IgniteThreadPoolSizeTest.java
 
b/modules/core/src/test/java/org/apache/ignite/thread/IgniteThreadPoolSizeTest.java
index cc1b25f3aac..21b0fa740ad 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/thread/IgniteThreadPoolSizeTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/thread/IgniteThreadPoolSizeTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.thread;
 
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -76,7 +77,8 @@ public class IgniteThreadPoolSizeTest extends 
GridCommonAbstractTest {
      */
     @Test
     public void testRebalanceThreadPoolSize() throws Exception {
-        
testWrongPoolSize(configuration().setRebalanceThreadPoolSize(WRONG_VALUE));
+        assertThrowsAnyCause(log, () -> 
Ignition.start(configuration().setRebalanceThreadPoolSize(WRONG_VALUE)),
+            IgniteException.class, "thread pool size");
     }
 
     /**
diff --git a/modules/extdata/logo/licenses/apache-2.0.txt 
b/modules/extdata/logo/licenses/apache-2.0.txt
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/modules/extdata/logo/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
diff --git a/modules/extdata/logo/pom.xml b/modules/extdata/logo/pom.xml
new file mode 100644
index 00000000000..b034378d5b1
--- /dev/null
+++ b/modules/extdata/logo/pom.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-parent-internal</artifactId>
+        <version>${revision}</version>
+        <relativePath>../../../parent-internal/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>ignite-extdata-logo</artifactId>
+    <url>https://ignite.apache.org</url>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-core</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+            <version>${spring.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+            <version>${spring.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <version>${spring.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-tools</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <version>2.8.2</version>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git 
a/modules/extdata/logo/src/test/java/org/apache/ignite/internal/IgniteExtendedLogoTest.java
 
b/modules/extdata/logo/src/test/java/org/apache/ignite/internal/IgniteExtendedLogoTest.java
new file mode 100644
index 00000000000..497d6202c3f
--- /dev/null
+++ 
b/modules/extdata/logo/src/test/java/org/apache/ignite/internal/IgniteExtendedLogoTest.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal;
+
+import org.apache.ignite.testframework.ListeningTestLogger;
+import org.apache.ignite.testframework.LogListener;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
+
+/** */
+public class IgniteExtendedLogoTest extends GridCommonAbstractTest {
+    /** @throws Exception If fails. */
+    @Test
+    public void testExtendedLogo() throws Exception {
+        ListeningTestLogger testLog = new ListeningTestLogger(log);
+
+        LogListener waitLogoLsnr = LogListener.matches("Ignite 
IgniteLogInfoProvider is used to customize the logo version output.")
+            .build();
+        testLog.registerListener(waitLogoLsnr);
+
+        startGrid(getConfiguration().setGridLogger(testLog));
+
+        assertTrue(waitForCondition(waitLogoLsnr::check, 5_000L));
+    }
+}
diff --git 
a/modules/extdata/logo/src/test/java/org/apache/ignite/internal/plugin/IgniteExtLogInfoProviderImpl.java
 
b/modules/extdata/logo/src/test/java/org/apache/ignite/internal/plugin/IgniteExtLogInfoProviderImpl.java
new file mode 100644
index 00000000000..826c7e333a1
--- /dev/null
+++ 
b/modules/extdata/logo/src/test/java/org/apache/ignite/internal/plugin/IgniteExtLogInfoProviderImpl.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.ignite.internal.plugin;
+
+import java.lang.management.RuntimeMXBean;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+import static org.apache.ignite.internal.IgniteKernal.NL;
+import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
+import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
+
+/**
+ * Change the message output for metrics log.
+ */
+public class IgniteExtLogInfoProviderImpl extends IgniteLogInfoProviderImpl {
+    /** {@inheritDoc} */
+    @Override void ackAsciiLogo(IgniteLogger log, IgniteConfiguration cfg, 
RuntimeMXBean rtBean) {
+        String ver = "ver. " + ACK_VER_STR;
+
+        U.quietAndInfo(log,
+            NL + NL +
+                ">>> Ignite IgniteLogInfoProvider is used to customize the 
logo version output. " + NL +
+                ">>> " + ver + NL +
+                ">>> " + cfg.getIgniteHome() + NL +
+                ">>> " + rtBean.getName() + NL +
+                ">>> " + COPYRIGHT + NL +
+                ">>> " + NL
+        );
+    }
+}
diff --git 
a/modules/extdata/logo/src/test/java/org/apache/ignite/internal/testsuites/IgniteLogoExtensionTestSuite.java
 
b/modules/extdata/logo/src/test/java/org/apache/ignite/internal/testsuites/IgniteLogoExtensionTestSuite.java
new file mode 100644
index 00000000000..36fea9f9d2f
--- /dev/null
+++ 
b/modules/extdata/logo/src/test/java/org/apache/ignite/internal/testsuites/IgniteLogoExtensionTestSuite.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.testsuites;
+
+import org.apache.ignite.internal.IgniteExtendedLogoTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Info provider test suite.
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+    IgniteExtendedLogoTest.class
+})
+public class IgniteLogoExtensionTestSuite {
+}
diff --git 
a/modules/extdata/logo/src/test/resources/META-INF/services/org.apache.ignite.internal.plugin.IgniteLogInfoProvider
 
b/modules/extdata/logo/src/test/resources/META-INF/services/org.apache.ignite.internal.plugin.IgniteLogInfoProvider
new file mode 100644
index 00000000000..b38541c6178
--- /dev/null
+++ 
b/modules/extdata/logo/src/test/resources/META-INF/services/org.apache.ignite.internal.plugin.IgniteLogInfoProvider
@@ -0,0 +1 @@
+org.apache.ignite.internal.plugin.IgniteExtLogInfoProviderImpl
diff --git a/pom.xml b/pom.xml
index b2a2ae944e1..d929058f5a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,6 +46,7 @@
         <module>modules/extdata/p2p</module>
         <module>modules/extdata/uri</module>
         <module>modules/extdata/platform</module>
+        <module>modules/extdata/logo</module>
         <module>modules/clients</module>
         <module>modules/spring</module>
         <module>modules/web</module>

Reply via email to