GEODE-7363: Add member type common tag

Co-authored-by: Dale Emery <demery@pivotal.io>
Co-authored-by: Mark Hanson <mhanson@pivotal.io>
diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/metrics/MemberTypeCommonTagsTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/metrics/MemberTypeCommonTagsTest.java
new file mode 100644
index 0000000..238ae2c
--- /dev/null
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/metrics/MemberTypeCommonTagsTest.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.metrics;
+
+import static java.io.File.pathSeparator;
+import static org.apache.geode.cache.execute.FunctionService.onMember;
+import static org.apache.geode.cache.execute.FunctionService.onServer;
+import static org.apache.geode.test.compiler.ClassBuilder.writeJarFromClasses;
+import static org.apache.geode.test.micrometer.MicrometerAssertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.Meter;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientCacheFactory;
+import org.apache.geode.cache.client.Pool;
+import org.apache.geode.cache.client.PoolManager;
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.rules.ServiceJarRule;
+import org.apache.geode.test.junit.rules.gfsh.GfshRule;
+
+public class MemberTypeCommonTagsTest {
+  private Path serverFolder;
+  private Pool serverPool;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public GfshRule gfshRule = new GfshRule();
+
+  @Rule
+  public ServiceJarRule serviceJarRule = new ServiceJarRule();
+  private ClientCache clientCache;
+  private Path locatorFolder;
+  private Cache cache;
+
+  @Test
+  public void theMemberTypeTag_forAnEmbeddedCache_isEmbeddedCache() {
+    SimpleMeterRegistry simpleMeterRegistry = new SimpleMeterRegistry();
+
+    try (Cache ignored = createEmbeddedCache(simpleMeterRegistry)) {
+      Gauge gauge = simpleMeterRegistry.find("jvm.buffer.memory.used").gauge();
+      assertThat(gauge).hasTag("member.type", "embedded-cache");
+    }
+  }
+
+  @Test
+  public void theMemberTypeTag_forAServer_isServer() throws IOException {
+    startServer("");
+
+    try {
+      assertThat(memberTypeTag(onServer(serverPool))).isEqualTo("server");
+    } finally {
+      stopServer();
+    }
+  }
+
+  @Test
+  public void theMemberTypeTag_forAMemberServerWithAnEmbeddedLocator_isServerLocator()
+      throws IOException {
+    startAMemberServerWithAnEmbeddedLocator();
+
+    try {
+      assertThat(memberTypeTag(onServer(serverPool))).isEqualTo("server-locator");
+    } finally {
+      stopServer();
+    }
+  }
+
+  @Test
+  public void theMemberTypeTag_forALocator_isLocator() throws IOException {
+    DistributedMember locator = startLocator();
+
+    try {
+      assertThat(memberTypeTag(onMember(locator))).isEqualTo("locator");
+    } finally {
+      stopLocator();
+    }
+  }
+
+  private Cache createEmbeddedCache(SimpleMeterRegistry simpleMeterRegistry) {
+    Properties properties = new Properties();
+    CacheFactory cacheFactory = new CacheFactory(properties);
+    return cacheFactory.addMeterSubregistry(simpleMeterRegistry).create();
+  }
+
+  private DistributedMember startLocator() throws IOException {
+    // need a locator for a test
+    locatorFolder = temporaryFolder.getRoot().toPath().toAbsolutePath();
+
+    int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(1);
+
+    int locatorPort = ports[0];
+
+    Path serviceJarPath = serviceJarRule.createJarFor("metrics-publishing-service.jar",
+        MetricsPublishingService.class, SimpleMetricsPublishingService.class);
+
+    Path functionJarPath = locatorFolder.resolve("function.jar").toAbsolutePath();
+    writeJarFromClasses(functionJarPath.toFile(), GetMemberTypeTag.class);
+
+    String startLocatorCommand = String.join(" ",
+        "start locator",
+        "--name=locator",
+        "--dir=" + locatorFolder,
+        "--port=" + locatorPort,
+        "--classpath=" + serviceJarPath + pathSeparator + functionJarPath,
+        "--bind-address=127.0.0.1",
+        "--http-service-port=7075");
+
+    gfshRule.execute(startLocatorCommand);
+
+    Properties properties = new Properties();
+    properties.setProperty(DistributionConfig.LOCATORS_NAME, "127.0.0.1[" + locatorPort + "]");
+    CacheFactory cacheFactory = new CacheFactory(properties);
+    cache = cacheFactory.create();
+
+    return cache.getDistributedSystem().findDistributedMember("locator");
+  }
+
+  private void stopLocator() {
+    cache.close();
+    String stopLocatorCommand = "stop locator --dir=" + locatorFolder;
+    gfshRule.execute(stopLocatorCommand);
+  }
+
+  private void startAMemberServerWithAnEmbeddedLocator() throws IOException {
+    // need to start a server with the "start-locator" variable
+    startServer("--J=-Dgemfire.start-locator=127.0.0.1[10335]");
+  }
+
+  private void startServer(String additionalParameters) throws IOException {
+    serverFolder = temporaryFolder.getRoot().toPath().toAbsolutePath();
+
+    int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(2);
+
+    int serverPort = ports[0];
+    int jmxRmiPort = ports[1];
+
+    Path serviceJarPath = serviceJarRule.createJarFor("metrics-publishing-service.jar",
+        MetricsPublishingService.class, SimpleMetricsPublishingService.class);
+
+    Path functionJarPath = serverFolder.resolve("function.jar").toAbsolutePath();
+    writeJarFromClasses(functionJarPath.toFile(), GetMemberTypeTag.class);
+
+    String startServerCommand = String.join(" ",
+        "start server",
+        "--name=server",
+        "--dir=" + serverFolder,
+        "--server-port=" + serverPort,
+        "--classpath=" + serviceJarPath + pathSeparator + functionJarPath,
+        "--J=-Dgemfire.enable-cluster-config=true",
+        "--J=-Dgemfire.jmx-manager=true",
+        "--J=-Dgemfire.jmx-manager-start=true",
+        "--J=-Dgemfire.jmx-manager-port=" + jmxRmiPort,
+        additionalParameters);
+
+    gfshRule.execute(startServerCommand);
+    clientCache = new ClientCacheFactory().addPoolServer("localhost", serverPort).create();
+
+    serverPool = PoolManager.createFactory()
+        .addServer("localhost", serverPort)
+        .create("server-pool");
+  }
+
+  private void stopServer() {
+    serverPool.destroy();
+    clientCache.close();
+
+    String stopServerCommand = "stop server --dir=" + serverFolder;
+    gfshRule.execute(stopServerCommand);
+  }
+
+  private String memberTypeTag(Execution execution) {
+    @SuppressWarnings("unchecked")
+    List<String> results = (List<String>) execution
+        .execute(new GetMemberTypeTag())
+        .getResult();
+    return results.get(0);
+  }
+
+  static class GetMemberTypeTag implements Function<String> {
+    private static final String ID = "GetMemberTypeTag";
+
+    @Override
+    public void execute(FunctionContext<String> context) {
+      String meterNameToCheck = "jvm.memory.used";
+
+      Meter meter = SimpleMetricsPublishingService.getRegistry()
+          .find(meterNameToCheck)
+          .meter();
+
+      String result = null;
+
+      if (meter != null) {
+        Map<String, String> tagsMap = meter.getId().getTags().stream()
+            .collect(Collectors.toMap(Tag::getKey, Tag::getValue));
+        result = tagsMap.get("member.type");
+      }
+
+      context.<String>getResultSender().lastResult(result);
+    }
+
+    @Override
+    public String getId() {
+      return ID;
+    }
+  }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsService.java b/geode-core/src/main/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsService.java
index 4f8b1c8..3f63f92 100644
--- a/geode-core/src/main/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsService.java
+++ b/geode-core/src/main/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsService.java
@@ -20,6 +20,7 @@
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.function.BooleanSupplier;
 import java.util.function.Supplier;
 
 import io.micrometer.core.instrument.MeterRegistry;
@@ -28,6 +29,8 @@
 import org.apache.logging.log4j.Logger;
 
 import org.apache.geode.annotations.VisibleForTesting;
+import org.apache.geode.distributed.Locator;
+import org.apache.geode.distributed.ServerLauncher;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
 import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.internal.util.CollectingServiceLoader;
@@ -65,8 +68,8 @@
         CollectingServiceLoader<MetricsPublishingService> publishingServiceLoader,
         CompositeMeterRegistry metricsServiceMeterRegistry,
         Collection<MeterRegistry> persistentMeterRegistries, CloseableMeterBinder binder,
-        InternalDistributedSystem system,
-        boolean isClient);
+        InternalDistributedSystem system, boolean isClient, boolean hasLocator,
+        boolean hasCacheServer);
   }
 
   @VisibleForTesting
@@ -74,14 +77,15 @@
       CollectingServiceLoader<MetricsPublishingService> publishingServiceLoader,
       CompositeMeterRegistry metricsServiceMeterRegistry,
       Collection<MeterRegistry> persistentMeterRegistries, CloseableMeterBinder binder,
-      InternalDistributedSystem system, boolean isClient) {
+      InternalDistributedSystem system, boolean isClient, boolean hasLocator,
+      boolean hasCacheServer) {
     this.builder = builder;
     this.logger = logger;
     this.meterRegistry = metricsServiceMeterRegistry;
     this.publishingServiceLoader = publishingServiceLoader;
     this.binder = binder;
     this.persistentMeterRegistries.addAll(persistentMeterRegistries);
-    meterRegistry.config().commonTags(commonTags(system, isClient));
+    addCommonTags(system, isClient, hasLocator, hasCacheServer);
   }
 
   /**
@@ -144,28 +148,49 @@
     meterRegistry.remove(subregistry);
   }
 
-  private static Set<Tag> commonTags(InternalDistributedSystem system, boolean isClient) {
-    Set<Tag> commonTags = new HashSet<>();
-
-    if (!isClient) {
-      String systemId = String.valueOf(system.getConfig().getDistributedSystemId());
-      commonTags.add(Tag.of("cluster", systemId));
-    }
+  private void addCommonTags(InternalDistributedSystem system, boolean isClient,
+      boolean hasLocators, boolean hasCacheServer) {
+    int clusterId = system.getConfig().getDistributedSystemId();
 
     String memberName = system.getName();
-    requireNonNull(memberName);
-    if (!memberName.isEmpty()) {
-      commonTags.add(Tag.of("member", memberName));
-    }
-
     String hostName = system.getDistributedMember().getHost();
-    requireNonNull(hostName);
+
+    requireNonNull(memberName, "Member Name is null.");
+    requireNonNull(hostName, "Host Name is null.");
 
     if (hostName.isEmpty()) {
       throw new IllegalArgumentException("Host name must not be empty");
     }
-    commonTags.add(Tag.of("host", hostName));
-    return commonTags;
+    Set<Tag> tags = new HashSet<>();
+
+    if (!isClient) {
+      tags.add(Tag.of("cluster", String.valueOf(clusterId)));
+
+    }
+
+    if (!memberName.isEmpty()) {
+      tags.add(Tag.of("member", memberName));
+    }
+
+    tags.add(Tag.of("host", hostName));
+    tags.add(Tag.of("member.type", memberTypeFor(hasLocators, hasCacheServer)));
+    meterRegistry.config().commonTags(tags);
+  }
+
+  private static String memberTypeFor(boolean hasLocator, boolean hasCacheServer) {
+    if (hasCacheServer && hasLocator) {
+      return "server-locator";
+    }
+
+    if (hasCacheServer) {
+      return "server";
+    }
+
+    if (hasLocator) {
+      return "locator";
+    }
+
+    return "embedded-cache";
   }
 
   private void startMetricsPublishingService(MetricsPublishingService service) {
@@ -216,12 +241,14 @@
     private Supplier<CollectingServiceLoader<MetricsPublishingService>> serviceLoaderSupplier =
         ListCollectingServiceLoader::new;
     private Set<MeterRegistry> persistentMeterRegistries = new HashSet<>();
+    private BooleanSupplier hasLocator = Locator::hasLocator;
+    private BooleanSupplier hasCacheServer = () -> ServerLauncher.getInstance() != null;
 
     @Override
     public MetricsService build(InternalDistributedSystem system) {
       return metricsServiceFactory.create(this, loggerSupplier.get(), serviceLoaderSupplier.get(),
           compositeRegistrySupplier.get(), persistentMeterRegistries, meterBinderSupplier.get(),
-          system, isClient);
+          system, isClient, hasLocator.getAsBoolean(), hasCacheServer.getAsBoolean());
     }
 
     @Override
@@ -249,12 +276,24 @@
     }
 
     @VisibleForTesting
+    Builder setCacheServerDetector(BooleanSupplier hasCacheServer) {
+      this.hasCacheServer = hasCacheServer;
+      return this;
+    }
+
+    @VisibleForTesting
     Builder setCompositeMeterRegistry(CompositeMeterRegistry registry) {
       compositeRegistrySupplier = () -> registry;
       return this;
     }
 
     @VisibleForTesting
+    Builder setLocatorDetector(BooleanSupplier hasLocator) {
+      this.hasLocator = hasLocator;
+      return this;
+    }
+
+    @VisibleForTesting
     Builder setLogger(Logger logger) {
       loggerSupplier = () -> logger;
       return this;
diff --git a/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceBuilderTest.java b/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceBuilderTest.java
index 4caf883..52caf9c 100644
--- a/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceBuilderTest.java
+++ b/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceBuilderTest.java
@@ -77,9 +77,9 @@
   public void usesFactoryToCreateSession_ifFactorySet() {
     MetricsService metricsServiceCreatedByFactory = mock(MetricsService.class);
 
-    when(
-        metricsServiceFactory.create(any(), any(), any(), any(), any(), any(), any(), anyBoolean()))
-            .thenReturn(metricsServiceCreatedByFactory);
+    when(metricsServiceFactory
+        .create(any(), any(), any(), any(), any(), any(), any(), anyBoolean(), anyBoolean(),
+            anyBoolean())).thenReturn(metricsServiceCreatedByFactory);
 
     MetricsService metricsService = serviceBuilder
         .setMetricsServiceFactory(metricsServiceFactory)
@@ -95,7 +95,8 @@
         .build(system);
 
     verify(metricsServiceFactory)
-        .create(same(serviceBuilder), any(), any(), any(), any(), any(), any(), anyBoolean());
+        .create(same(serviceBuilder), any(), any(), any(), any(), any(), any(), anyBoolean(),
+            anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -108,7 +109,8 @@
         .build(system);
 
     verify(metricsServiceFactory)
-        .create(any(), any(), same(theServiceLoader), any(), any(), any(), any(), anyBoolean());
+        .create(any(), any(), same(theServiceLoader), any(), any(), any(), any(), anyBoolean(),
+            anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -119,7 +121,7 @@
 
     verify(metricsServiceFactory)
         .create(any(), any(), any(CollectingServiceLoader.class), any(), any(), any(), any(),
-            anyBoolean());
+            anyBoolean(), anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -132,7 +134,7 @@
 
     verify(metricsServiceFactory)
         .create(any(), any(), any(), same(theMetricsServiceMeterRegistry), any(), any(), any(),
-            anyBoolean());
+            anyBoolean(), anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -142,7 +144,7 @@
 
     verify(metricsServiceFactory)
         .create(any(), any(), any(), any(CompositeMeterRegistry.class), any(), any(), any(),
-            anyBoolean());
+            anyBoolean(), anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -159,7 +161,7 @@
 
     verify(metricsServiceFactory)
         .create(any(), any(), any(), any(), clientMeterRegistriesPassedToFactory.capture(), any(),
-            any(), anyBoolean());
+            any(), anyBoolean(), anyBoolean(), anyBoolean());
 
     assertThat(clientMeterRegistriesPassedToFactory.getValue())
         .containsExactlyInAnyOrderElementsOf(individuallyAddedClientMeterRegistries);
@@ -179,7 +181,7 @@
 
     verify(metricsServiceFactory)
         .create(any(), any(), any(), any(), clientMeterRegistriesPassedToFactory.capture(), any(),
-            any(), anyBoolean());
+            any(), anyBoolean(), anyBoolean(), anyBoolean());
 
     assertThat(clientMeterRegistriesPassedToFactory.getValue())
         .containsExactlyInAnyOrderElementsOf(bulkAddedClientMeterRegistries);
@@ -196,7 +198,7 @@
 
     verify(metricsServiceFactory)
         .create(any(), any(), any(), any(), clientMeterRegistriesPassedToFactory.capture(), any(),
-            any(), anyBoolean());
+            any(), anyBoolean(), anyBoolean(), anyBoolean());
 
     assertThat(clientMeterRegistriesPassedToFactory.getValue())
         .isEmpty();
@@ -211,7 +213,8 @@
         .build(system);
 
     verify(metricsServiceFactory)
-        .create(any(), any(), any(), any(), any(), same(theBinder), any(), anyBoolean());
+        .create(any(), any(), any(), any(), any(), same(theBinder), any(), anyBoolean(),
+            anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -221,7 +224,7 @@
 
     verify(metricsServiceFactory)
         .create(any(), any(), any(), any(), any(), any(StandardMeterBinder.class), any(),
-            anyBoolean());
+            anyBoolean(), anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -233,7 +236,45 @@
         .build(system);
 
     verify(metricsServiceFactory)
-        .create(any(), same(theLogger), any(), any(), any(), any(), any(), anyBoolean());
+        .create(any(), same(theLogger), any(), any(), any(), any(), any(), anyBoolean(),
+            anyBoolean(), anyBoolean());
+  }
+
+  @Test
+  public void usesGivenLocatorDetectorToDetectLocator() {
+    serviceBuilder.setMetricsServiceFactory(metricsServiceFactory)
+        .setLocatorDetector(() -> true)
+        .build(system);
+
+    verify(metricsServiceFactory)
+        .create(any(), any(), any(), any(), any(), any(), any(), anyBoolean(), eq(true),
+            anyBoolean());
+
+    serviceBuilder.setLocatorDetector(() -> false)
+        .build(system);
+
+    verify(metricsServiceFactory)
+        .create(any(), any(), any(), any(), any(), any(), any(), anyBoolean(), eq(false),
+            anyBoolean());
+  }
+
+  @Test
+  public void usesGivenCacheServerDetectorToDetectCacheServer() {
+    serviceBuilder.setMetricsServiceFactory(metricsServiceFactory)
+        .setCacheServerDetector(() -> true)
+        .build(system);
+
+    verify(metricsServiceFactory)
+        .create(any(), any(), any(), any(), any(), any(), any(), anyBoolean(), anyBoolean(),
+            eq(true));
+
+    serviceBuilder
+        .setCacheServerDetector(() -> false)
+        .build(system);
+
+    verify(metricsServiceFactory)
+        .create(any(), any(), any(), any(), any(), any(), any(), anyBoolean(), anyBoolean(),
+            eq(false));
   }
 
   @Test
@@ -242,7 +283,8 @@
         .build(system);
 
     verify(metricsServiceFactory)
-        .create(any(), any(Logger.class), any(), any(), any(), any(), any(), anyBoolean());
+        .create(any(), any(Logger.class), any(), any(), any(), any(), any(), anyBoolean(),
+            anyBoolean(), anyBoolean());
   }
 
   @Test
@@ -252,7 +294,8 @@
         .build(system);
 
     verify(metricsServiceFactory)
-        .create(any(), any(), any(), any(), any(), any(), any(), eq(true));
+        .create(any(), any(), any(), any(), any(), any(), any(), eq(true), anyBoolean(),
+            anyBoolean());
   }
 
   @Test
@@ -261,7 +304,8 @@
         .build(system);
 
     verify(metricsServiceFactory)
-        .create(any(), any(), any(), any(), any(), any(), any(), eq(false));
+        .create(any(), any(), any(), any(), any(), any(), any(), eq(false), anyBoolean(),
+            anyBoolean());
   }
 
   @Test
@@ -272,7 +316,8 @@
         .build(theSystem);
 
     verify(metricsServiceFactory)
-        .create(any(), any(), any(), any(), any(), any(), same(theSystem), anyBoolean());
+        .create(any(), any(), any(), any(), any(), any(), same(theSystem), anyBoolean(),
+            anyBoolean(), anyBoolean());
   }
 
   private static <T> Set<T> setOf(int count, Class<? extends T> type) {
diff --git a/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceTest.java b/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceTest.java
index 19e25b0..3e35638 100644
--- a/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceTest.java
+++ b/geode-core/src/test/java/org/apache/geode/metrics/internal/InternalDistributedSystemMetricsServiceTest.java
@@ -96,7 +96,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, theMetricsServiceMeterRegistry, emptyList(), meterBinder,
-            system, false);
+            system, false, false, true);
 
     assertThat(metricsService.getMeterRegistry())
         .isSameAs(theMetricsServiceMeterRegistry);
@@ -109,7 +109,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(theMetricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder,
-            system, false);
+            system, false, false, true);
 
     assertThat(metricsService.getRebuilder())
         .isSameAs(theMetricsServiceBuilder);
@@ -122,7 +122,7 @@
     assertThatThrownBy(() -> metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder,
-            system, false)).isInstanceOf(NullPointerException.class);
+            system, false, false, true)).isInstanceOf(NullPointerException.class);
   }
 
   @Test
@@ -132,9 +132,8 @@
     assertThatThrownBy(
         () -> metricsService =
             new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
-                publishingServiceLoader,
-                metricsServiceMeterRegistry, emptyList(), meterBinder, system, false))
-                    .isInstanceOf(IllegalArgumentException.class);
+                publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder,
+                system, false, false, true)).isInstanceOf(IllegalArgumentException.class);
   }
 
   @Test
@@ -144,7 +143,7 @@
     assertThatThrownBy(() -> metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder,
-            system, false)).isInstanceOf(NullPointerException.class);
+            system, false, false, true)).isInstanceOf(NullPointerException.class);
   }
 
   @Test
@@ -155,7 +154,7 @@
     MetricsService metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
-            false);
+            false, false, true);
 
     Meter meter = metricsService.getMeterRegistry()
         .counter("my.meter");
@@ -171,7 +170,7 @@
     MetricsService metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
-            false);
+            false, false, true);
 
     Meter meter = metricsService.getMeterRegistry()
         .counter("my.meter");
@@ -189,7 +188,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
-            false);
+            false, false, true);
 
     Meter meter = metricsService.getMeterRegistry()
         .counter("my.meter");
@@ -207,7 +206,7 @@
     MetricsService metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
-            false);
+            false, false, true);
 
     Meter meter = metricsService.getMeterRegistry()
         .counter("my.meter");
@@ -224,7 +223,7 @@
     MetricsService metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
-            true);
+            true, false, true);
 
     Meter meter = metricsService.getMeterRegistry()
         .counter("my.meter");
@@ -234,13 +233,80 @@
   }
 
   @Test
+  public void meterRegistry_registerMeter_addsLocatorMemberTypeTag_ifHasLocatorAndHasNoCacheServer() {
+    boolean hasCacheServer = false;
+    boolean hasLocator = true;
+
+
+    MetricsService metricsService =
+        new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
+            publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
+            true, hasLocator, hasCacheServer);
+
+    Meter meter = metricsService.getMeterRegistry()
+        .counter("my.meter");
+
+    assertThat(meter)
+        .hasTag("member.type", "locator");
+  }
+
+  @Test
+  public void meterRegistry_registerMeter_addsServerMemberTypeTag_ifHasCacheServerAndHasNoLocator() {
+    boolean hasCacheServer = true;
+    boolean hasLocator = false;
+
+    MetricsService metricsService =
+        new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
+            publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
+            true, hasLocator, hasCacheServer);
+
+    Meter meter = metricsService.getMeterRegistry()
+        .counter("my.meter");
+
+    assertThat(meter)
+        .hasTag("member.type", "server");
+  }
+
+  @Test
+  public void meterRegistry_registerMeter_addsEmbeddedCacheMemberTypeTag_ifHasNoCacheServerAndHasNoLocator() {
+    boolean hasCacheServer = false;
+    boolean hasLocator = false;
+
+    MetricsService metricsService =
+        new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
+            publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
+            true, hasLocator, hasCacheServer);
+    Meter meter = metricsService.getMeterRegistry()
+        .counter("my.meter");
+
+    assertThat(meter)
+        .hasTag("member.type", "embedded-cache");
+  }
+
+  @Test
+  public void meterRegistry_registerMeter_addsServerLocatorMemberTypeTag_ifHasLocatorAndHasCacheServer() {
+    boolean hasLocator = true;
+    boolean hasCacheServer = true;
+
+    MetricsService metricsService =
+        new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
+            publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
+            true, hasLocator, hasCacheServer);
+    Meter meter = metricsService.getMeterRegistry()
+        .counter("my.meter");
+
+    assertThat(meter)
+        .hasTag("member.type", "server-locator");
+  }
+
+  @Test
   public void start_addsPersistentMeterRegistriesToMetricsServiceMeterRegistry() {
     Set<MeterRegistry> thePersistentMeterRegistries = setOf(3, MeterRegistry.class);
 
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, thePersistentMeterRegistries,
-            meterBinder, system, false);
+            meterBinder, system, false, false, true);
 
     metricsService.start();
 
@@ -255,7 +321,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, theMetricsServiceMeterRegistry, emptyList(), meterBinder,
-            system, false);
+            system, false, false, true);
 
     metricsService.start();
 
@@ -276,7 +342,7 @@
 
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger, serviceLoader,
-            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false);
+            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false, false, true);
 
     metricsService.start();
 
@@ -301,7 +367,7 @@
 
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger, serviceLoader,
-            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false);
+            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false, false, true);
 
     metricsService.start();
 
@@ -319,7 +385,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, theMetricsServiceMeterRegistry, emptyList(), meterBinder,
-            system, false);
+            system, false, false, true);
 
     metricsService.start();
 
@@ -349,7 +415,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, persistentMeterRegistries,
-            binderThatAddsManyMeters, system, false);
+            binderThatAddsManyMeters, system, false, false, true);
 
     metricsService.start();
 
@@ -372,7 +438,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptySet(),
-            binderThatAddsManyMeters, system, false);
+            binderThatAddsManyMeters, system, false, false, true);
 
     metricsService.start();
 
@@ -402,7 +468,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), theMeterBinder,
-            system, false);
+            system, false, false, true);
 
     metricsService.start();
 
@@ -425,7 +491,7 @@
 
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger, serviceLoader,
-            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false);
+            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false, false, true);
 
     metricsService.start();
 
@@ -448,7 +514,7 @@
 
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger, serviceLoader,
-            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false);
+            metricsServiceMeterRegistry, emptyList(), meterBinder, system, false, false, true);
 
     metricsService.start();
 
@@ -475,7 +541,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, theMetricsServiceMeterRegistry, persistentMeterRegistries,
-            meterBinder, system, false);
+            meterBinder, system, false, false, true);
 
     metricsService.start();
 
@@ -493,7 +559,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, persistentMeterRegistries,
-            meterBinder, system, false);
+            meterBinder, system, false, false, true);
 
     metricsService.start();
 
@@ -508,7 +574,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, metricsServiceMeterRegistry, emptyList(), meterBinder, system,
-            false);
+            false, false, true);
 
     metricsService.start();
 
@@ -527,8 +593,7 @@
     metricsService =
         new InternalDistributedSystemMetricsService(metricsServiceBuilder, logger,
             publishingServiceLoader, theMetricsServiceMeterRegistry, emptyList(), meterBinder,
-            system,
-            false);
+            system, false, false, true);
 
     metricsService.start();
     metricsService.stop();