Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gRPC JMX metrics #13112

Merged
merged 5 commits into from
Aug 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-include= ~${workspace}/cnf/resources/bnd/feature.props
symbolicName=io.openliberty.grpcMonitor-1.0
Manifest-Version: 1.0
IBM-API-Package: io.openliberty.grpc.monitor; type="ibm-api"
IBM-Provision-Capability: \
osgi.identity; filter:="(&(type=osgi.subsystem.feature)(osgi.identity=com.ibm.websphere.appserver.monitor-1.0))", \
osgi.identity; filter:="(&(type=osgi.subsystem.feature)(|(osgi.identity=io.openliberty.grpc-1.0)(osgi.identity=io.openliberty.grpcClient-1.0)))"
IBM-Install-Policy: when-satisfied
-bundles=io.openliberty.grpc.1.0.internal.monitor
kind=beta
edition=full

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
@SuiteClasses({
HelloWorldCDITests.class,
HelloWorldTest.class,
GrpcMetricsTest.class,
ServiceSupportTests.class,
ServiceConfigTests.class,
ServiceInterceptorTests.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*******************************************************************************
* Copyright (c) 2020 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/

package com.ibm.ws.fat.grpc;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import com.ibm.websphere.simplicity.ShrinkHelper;
import com.ibm.websphere.simplicity.log.Log;

import componenttest.annotation.Server;
import componenttest.custom.junit.runner.FATRunner;
import componenttest.topology.impl.LibertyServer;
import componenttest.topology.utils.FATServletClient;

@RunWith(FATRunner.class)
public class GrpcMetricsTest extends FATServletClient {

protected static final Class<?> c = GrpcMetricsTest.class;

@Rule
public TestName name = new TestName();

@Server("HelloWorldServer")
public static LibertyServer grpcMetricsServer; //GrpcMetricsServer

@BeforeClass
public static void setUp() throws Exception {
// add all classes from com.ibm.ws.grpc.fat.helloworld.service and io.grpc.examples.helloworld
// to a new app HelloWorldService.war
ShrinkHelper.defaultDropinApp(grpcMetricsServer, "HelloWorldService.war",
"com.ibm.ws.grpc.fat.helloworld.service",
"io.grpc.examples.helloworld");

// add all classes from com.ibm.ws.grpc.fat.helloworld.client, io.grpc.examples.helloworld,
// and com.ibm.ws.fat.grpc.tls to a new app HelloWorldClient.war.
ShrinkHelper.defaultDropinApp(grpcMetricsServer, "HelloWorldClient.war",
"com.ibm.ws.grpc.fat.helloworld.client",
"io.grpc.examples.helloworld",
"com.ibm.ws.fat.grpc.tls");

grpcMetricsServer.startServer(GrpcMetricsTest.class.getSimpleName() + ".log");
assertNotNull("CWWKO0219I.*ssl not recieved", grpcMetricsServer.waitForStringInLog("CWWKO0219I.*ssl"));
}

@AfterClass
public static void tearDown() throws Exception {
grpcMetricsServer.stopServer();
}

/**
* Tests gRPC server-side and client-side metrics.
*
* @throws Exception
*/
@Test
public void testGrpcMetrics() throws Exception {
String contextRoot = "HelloWorldClient";
try (WebClient webClient = new WebClient()) {

// Construct the URL for the test
URL url = GrpcTestUtils.createHttpUrl(grpcMetricsServer, contextRoot, "grpcClient");

HtmlPage page = (HtmlPage) webClient.getPage(url);

// Log the page for debugging if necessary in the future.
Log.info(c, name.getMethodName(), page.asText());
Log.info(c, name.getMethodName(), page.asXml());

assertTrue("the servlet was not loaded correctly",
page.asText().contains("gRPC helloworld client example"));

HtmlForm form = page.getFormByName("form1");

// set a name, which we'll expect the RPC to return
HtmlTextInput inputText = (HtmlTextInput) form.getInputByName("user");
inputText.setValueAttribute("us3r1");

// set the port
HtmlTextInput inputPort = (HtmlTextInput) form.getInputByName("port");
inputPort.setValueAttribute(String.valueOf(grpcMetricsServer.getHttpDefaultPort()));

// set the hostname
HtmlTextInput inputHost = (HtmlTextInput) form.getInputByName("address");
inputHost.setValueAttribute(grpcMetricsServer.getHostname());

// submit, and execute the RPC
HtmlSubmitInput submitButton = form.getInputByName("submit");
page = submitButton.click();

// check the gRPC client-side metrics
checkMetric("/metrics/vendor/grpc.client.rpcStarted.total", "1");
checkMetric("/metrics/vendor/grpc.client.rpcCompleted.total", "1");
checkMetric("/metrics/vendor/grpc.client.sentMessages.total", "1");
checkMetric("/metrics/vendor/grpc.client.receivedMessages.total", "1");

// check the gRPC server-side metrics
checkMetric("/metrics/vendor/grpc.server.rpcStarted.total", "1");
checkMetric("/metrics/vendor/grpc.server.rpcCompleted.total", "1");
checkMetric("/metrics/vendor/grpc.server.sentMessages.total", "1");
checkMetric("/metrics/vendor/grpc.server.receivedMessages.total", "1");

// Log the page for debugging if necessary in the future.
Log.info(c, name.getMethodName(), page.asText());
assertTrue("the gRPC request did not complete correctly", page.asText().contains("us3r1"));
}
}

/**
* Verifies the given metric by comparing the actual value with the given value
*
* @param metricName - the metric to verify
* @param expectedValue - the expected value
* @return the actual value received from the Metrics endpoint
*/
private String checkMetric(String metricName, String expectedValue) {
HttpURLConnection con = null;
try {
URL url = new URL("http://" + grpcMetricsServer.getHostname() + ":" + grpcMetricsServer.getHttpDefaultPort() + metricName);
int retcode;
con = (HttpURLConnection) url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestMethod("GET");

retcode = con.getResponseCode();
if (retcode != 200) {
fail("Bad return code from Metrics method call. Expected 200, got " + retcode);

return null;
}

InputStream is = con.getInputStream();
InputStreamReader isr = new InputStreamReader(is);

BufferedReader br = new BufferedReader(isr);

String metricValue = null;
for (String line = br.readLine(); line != null; line = br.readLine()) {
if (!line.startsWith("#")) {
String[] mertricAttr = line.split(" ");
if (mertricAttr.length > 0) {
metricValue = mertricAttr[mertricAttr.length - 1];
break;
}
}
}

if (metricValue == null || !metricValue.equals(expectedValue)) {
fail(String.format("Incorrect metric value [%s]. Expected [%s], got [%s]", metricName, expectedValue, metricValue));
}
return metricValue;

} catch (Exception e) {
fail("Caught unexpected exception: " + e);
return null;
} finally {
if (con != null) {
con.disconnect();
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<grpcTarget target="test.g3store.grpc.AppConsumerService/getAppInfo" headersToPropagate="authorization"/>
<grpcTarget target="test.g3store.grpc.AppConsumerService/getAllAppNames" authnToken="jwt"/>




</server>
</server>
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
<include location="../fatTestPorts.xml"/>

<javaPermission className="java.security.AllPermission" name="*" actions="*" />
</server>
</server>
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
<include location="../fatTestPorts.xml"/>

<javaPermission className="java.security.AllPermission" name="*" actions="*" />
</server>
</server>
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@

Contributors:
IBM Corporation - initial API and implementation
-->
-->
<server>
<featureManager>
<feature>grpc-1.0</feature>
<feature>grpcClient-1.0</feature>
<feature>ssl-1.0</feature>
<feature>monitor-1.0</feature>
<feature>mpMetrics-2.3</feature>
</featureManager>

<mpMetrics authentication = "false"/>
<keyStore id="defaultKeyStore" password="passw0rd" />

<include location="../fatTestPorts.xml"/>

<javaPermission className="java.security.AllPermission" name="*" actions="*" />
</server>
<logging
traceSpecification="*=info=enabled:io.openliberty.grpc*=all"
maxFileSize="40" maxFiles="1" traceFormat="BASIC" />
</server>
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@
traceSpecification="*=info=enabled:io.openliberty.grpc*=all:com.ibm.testapp.g3store*=all"
maxFileSize="40" maxFiles="20" traceFormat="BASIC" />

</server>
</server>
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@
</application-bnd>
</application>

</server>
</server>
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@
<javaPermission className="java.security.AllPermission" name="*" actions="*" />

<!-- logging maxFileSize="200" maxFiles="3" traceFileName="grpcTrace.log" traceSpecification="*=info:com.ibm.ws.webcontainer*=all:com.ibm.wsspi.webcontainer*=all:HTTPChannel=all:TCPChannel=all:com.ibm.ws.http*=all"/ -->
</server>
</server>
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,4 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)

stopService();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class MappingTable {
public static final String SESSION_TAG_NAME = "appname";
public static final String JAXWS_SERVER_TAG_NAME = "endpoint";
public static final String JAXWS_CLIENT_TAG_NAME = "endpoint";
public static final String GRPC_SERVER_TAG_NAME = "grpc";
public static final String GRPC_CLIENT_TAG_NAME = "grpc";

public static final String COUNTER = MetricType.COUNTER.toString().toUpperCase();
public static final String GAUGE = MetricType.GAUGE.toString().toUpperCase();
Expand Down Expand Up @@ -117,6 +119,22 @@ private MappingTable() {
{ "vendor", "jaxws.client.responseTime.total", "Total Response Time", "jaxws.responseTime.total.description", GAUGE, MetricUnits.MILLISECONDS, "TotalHandlingTime", null, JAXWS_CLIENT_TAG_NAME }
};
mappingTable.put("WebSphere:feature=jaxws,*,type=Performance.Counter.Client", jaxwsClientTable);

String[][] grpcServerTable = new String[][]{
{ "vendor", "grpc.server.rpcStarted.total", "Total Server RPCs Started Count", "grpc.server.rpcStarted.total.description", COUNTER, MetricUnits.NONE, "RpcStartedCount", null, GRPC_SERVER_TAG_NAME },
{ "vendor", "grpc.server.rpcCompleted.total", "Total Server RPCs Completed Count", "grpc.server.rpcCompleted .total.description", COUNTER, MetricUnits.NONE, "RpcCompletedCount", null, GRPC_SERVER_TAG_NAME },
{ "vendor", "grpc.server.sentMessages.total", "Total Sent Stream Messages", "grpc.server.sentMessages.total.description", COUNTER, MetricUnits.NONE, "SentMessagesCount", null, GRPC_SERVER_TAG_NAME },
{ "vendor", "grpc.server.receivedMessages.total", "Total Received Stream Messages", "grpc.server.receivedMessages.total.description", COUNTER, MetricUnits.NONE, "ReceivedMessagesCount", null, GRPC_SERVER_TAG_NAME }
};
mappingTable.put("WebSphere:type=GrpcServerStats,name=*", grpcServerTable);

String[][] grpcClientTable = new String[][]{
{ "vendor", "grpc.client.rpcStarted.total", "Total Client RPCs Started Count", "grpc.client.rpcStarted.total.description", COUNTER, MetricUnits.NONE, "RpcStartedCount", null, GRPC_SERVER_TAG_NAME },
{ "vendor", "grpc.client.rpcCompleted.total", "Total Client RPCs Completed Count", "grpc.client.rpcCompleted.total.description", COUNTER, MetricUnits.NONE, "RpcCompletedCount", null, GRPC_SERVER_TAG_NAME },
{ "vendor", "grpc.client.sentMessages.total", "Total Sent Stream Messages", "grpc.client.sentMessages.total.description", COUNTER, MetricUnits.NONE, "SentMessagesCount", null, GRPC_SERVER_TAG_NAME },
{ "vendor", "grpc.client.receivedMessages.total", "Total Received Stream Messages", "grpc.client.receivedMessages.total.description", COUNTER, MetricUnits.NONE, "ReceivedMessagesCount", null, GRPC_SERVER_TAG_NAME }
};
mappingTable.put("WebSphere:type=GrpcClientStats,name=*", grpcClientTable);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ session.activeSessions.description=The number of concurrently active sessions. (
session.invalidated.total.description=The number of sessions that have logged out since this metric was enabled.
session.invalidatedbyTimeout.total.description=The number of sessions that have logged out by timeout since this metric was enabled.

grpc.server.rpcStarted.total.description=The total number of RPCs started on the server.
grpc.server.rpcCompleted.total.description=The total number of RPCs completed on the server, regardless of success or failure.
grpc.server.sentMessages.total.description=The total number of stream messages sent by the server.
grpc.server.receivedMessages.total.description=The total number of stream messages received from the client.

grpc.client.rpcStarted.total.description=The total number of RPCs started on the client.
grpc.client.rpcCompleted.total.description=The total number of RPCs completed on the client, regardless of success or failure.
grpc.client.sentMessages.total.description=The total number of stream messages sent by the client.
grpc.client.receivedMessages.total.description=The total number of stream messages received from the server.

REST.request.description=The number of invocations and total response time of this RESTful resource method since the start of the server.
#-----------------------------------------------------------------------------------------------------------------------------
Expand Down
17 changes: 16 additions & 1 deletion dev/io.openliberty.grpc.1.0.internal.client/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,23 @@ Import-Package: !sun.*,\
!org.eclipse.jetty.*,\
!org.jboss.*,\
javax.annotation;version=!,\
!com.ibm.websphere.monitor.jmx,\
*

# Use dynamic import of monitor packages to support indepndent/dynamic enablement of monitor feature
DynamicImport-Package: com.ibm.websphere.monitor.meters;version="1.0.0", \
com.ibm.websphere.monitor.jmx;version="1.0.0", \
com.ibm.wsspi.request.probe.bci, \
com.ibm.wsspi.probeExtension, \
io.openliberty.grpc.internal.monitor

Export-Package: \
io.openliberty.grpc.internal.client.* ,\
io.grpc.netty.shaded.io.*

-dsannotations: io.openliberty.grpc.internal.client.config.GrpcClientConfigImpl
-dsannotations: \
io.openliberty.grpc.internal.client.config.GrpcClientConfigImpl,\
io.openliberty.grpc.internal.client.GrpcClientComponent

# include the service providers and metatype
Include-Resource: \
Expand All @@ -65,16 +75,21 @@ Provide-Capability: osgi.serviceloader;osgi.serviceloader=io.grpc.ManagedChannel
instrument.disabled: true

-buildpath: \
com.ibm.ws.container.service;version=latest,\
com.ibm.websphere.javaee.servlet.4.0;version=latest,\
com.ibm.websphere.security;version=latest,\
com.ibm.ws.container.service;version=latest,\
com.ibm.ws.managedobject;version=latest,\
com.ibm.ws.webcontainer;version=latest,\
com.ibm.ws.logging.core;version=latest,\
com.ibm.ws.monitor;version=latest,\
com.ibm.websphere.org.osgi.core;version=latest,\
com.ibm.websphere.org.osgi.service.component;version=latest,\
com.ibm.ws.org.osgi.annotation.versioning;version=latest,\
com.ibm.wsspi.org.osgi.service.component.annotations;version=latest,\
com.ibm.ws.kernel.boot;version=latest,\
com.ibm.ws.kernel.service;version=latest,\
com.ibm.ws.kernel.feature;version=latest,\
org.osgi.service.component.annotations;version=latest,\
io.grpc:grpc-netty-shaded;version=1.27.0,\
io.openliberty.grpc.1.0.internal.common;version=latest,\
Expand Down
Loading