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

Collect WebLogic specific attributes #81

Merged
merged 2 commits into from
Jan 26, 2021
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
7 changes: 7 additions & 0 deletions instrumentation/weblogic/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
id "java"
}

dependencies {
compileOnly('javax.servlet:servlet-api:2.2')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright Splunk Inc.
*
* 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.
*/

package com.splunk.opentelemetry.middleware.weblogic;

import com.splunk.opentelemetry.javaagent.bootstrap.MiddlewareHolder;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;

public class WebLogicAttributeCollector {
private static final String CONTEXT_ATTRIBUTE_NAME = "otel.weblogic.attributes";
public static final String REQUEST_ATTRIBUTE_NAME = "otel.middleware";

public static void attachMiddlewareAttributes(HttpServletRequest servletRequest) {
WebLogicEntity.Request request = WebLogicEntity.Request.wrap(servletRequest);

Map<?, ?> attributes = fetchMiddlewareAttributes(request.getContext());
request.instance.setAttribute(REQUEST_ATTRIBUTE_NAME, attributes);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering: have you considered adding a field to MiddlewareHolder and storing those attributes there instead of the request?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server and application fields may have different values in a single JVM, so the current static field approach MiddlewareHolder would not work there.

}

private static Map<?, ?> fetchMiddlewareAttributes(WebLogicEntity.Context context) {
if (context.instance == null) {
return null;
}

Object value = context.instance.getAttribute(CONTEXT_ATTRIBUTE_NAME);

if (value instanceof Map<?, ?>) {
return (Map<?, ?>) value;
}

// Do this here to avoid duplicate work
storeMiddlewareIdentity(context);

Map<String, String> middleware = collectMiddlewareAttributes(context);
context.instance.setAttribute(CONTEXT_ATTRIBUTE_NAME, middleware);
return middleware;
}

private static void storeMiddlewareIdentity(WebLogicEntity.Context context) {
MiddlewareHolder.trySetName("WebLogic Server");
MiddlewareHolder.trySetVersion(detectVersion(context));
}

private static Map<String, String> collectMiddlewareAttributes(WebLogicEntity.Context context) {
WebLogicEntity.Bean applicationBean = context.getBean();
WebLogicEntity.Bean webServerBean = context.getServer().getBean();
WebLogicEntity.Bean serverBean = webServerBean.getParent();
WebLogicEntity.Bean clusterBean = WebLogicEntity.Bean.wrap(serverBean.getAttribute("Cluster"));
WebLogicEntity.Bean domainBean = serverBean.getParent();

Map<String, String> attributes = new HashMap<>();
attributes.put("middleware.weblogic.domain", domainBean.getName());
attributes.put("middleware.weblogic.cluster", clusterBean.getName());
attributes.put("middleware.weblogic.server", webServerBean.getName());
attributes.put("middleware.weblogic.application", applicationBean.getName());

return attributes;
}

private static String detectVersion(WebLogicEntity.Context context) {
String serverInfo = context.instance.getServerInfo();

if (serverInfo != null) {
for (String token : serverInfo.split(" ")) {
if (token.length() > 0 && Character.isDigit(token.charAt(0))) {
return token;
}
}
}

return "";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
/*
* Copyright Splunk Inc.
*
* 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.
*/

package com.splunk.opentelemetry.middleware.weblogic;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;

/** Provides wrappers around WebLogic internal class instances. */
public class WebLogicEntity {
private static final MethodHandle REQUEST_GET_CONTEXT;
private static final MethodHandle CONTEXT_GET_MBEAN;
private static final MethodHandle CONTEXT_GET_SERVER;
private static final MethodHandle SERVER_GET_MBEAN;
private static final MethodHandle MBEAN_GET_PARENT;
private static final MethodHandle MBEAN_GET_KEY;
private static final Class<?> MBEAN_CLASS;
private static final MethodHandle MBEAN_GET_ATTRIBUTE;

static {
MethodHandle requestGetContext;
MethodHandle contextGetMBean;
MethodHandle contextGetServer;
MethodHandle serverGetMBean;
MethodHandle mbeanGetParent;
MethodHandle mbeanGetKey;
MethodHandle mbeanGetAttribute;
Class<?> mbeanClass;

try {
requestGetContext =
MethodHandles.publicLookup()
.findVirtual(
Class.forName("weblogic.servlet.internal.ServletRequestImpl"),
"getContext",
MethodType.methodType(
Class.forName("weblogic.servlet.internal.WebAppServletContext")));
vovencij marked this conversation as resolved.
Show resolved Hide resolved
} catch (Exception e) {
requestGetContext = null;
}

REQUEST_GET_CONTEXT = requestGetContext;

try {
contextGetMBean =
MethodHandles.publicLookup()
.findVirtual(
Class.forName("weblogic.servlet.internal.WebAppServletContext"),
"getMBean",
MethodType.methodType(
Class.forName("weblogic.management.configuration.WebAppComponentMBean")));
} catch (Exception e) {
contextGetMBean = null;
}

CONTEXT_GET_MBEAN = contextGetMBean;

try {
contextGetServer =
MethodHandles.publicLookup()
.findVirtual(
Class.forName("weblogic.servlet.internal.WebAppServletContext"),
"getServer",
MethodType.methodType(Class.forName("weblogic.servlet.internal.HttpServer")));
} catch (Exception e) {
contextGetServer = null;
}

CONTEXT_GET_SERVER = contextGetServer;

try {
serverGetMBean =
MethodHandles.publicLookup()
.findVirtual(
Class.forName("weblogic.servlet.internal.HttpServer"),
"getMBean",
MethodType.methodType(
Class.forName("weblogic.management.configuration.WebServerMBean")));
} catch (Exception e) {
serverGetMBean = null;
}

SERVER_GET_MBEAN = serverGetMBean;

try {
mbeanGetParent =
MethodHandles.publicLookup()
.findVirtual(
Class.forName("weblogic.descriptor.DescriptorBean"),
"getParentBean",
MethodType.methodType(Class.forName("weblogic.descriptor.DescriptorBean")));
} catch (Exception e) {
mbeanGetParent = null;
}

MBEAN_GET_PARENT = mbeanGetParent;

try {
mbeanGetKey =
MethodHandles.publicLookup()
.findVirtual(
Class.forName("weblogic.descriptor.internal.AbstractDescriptorBean"),
"_getKey",
MethodType.methodType(Object.class));
} catch (Exception e) {
mbeanGetKey = null;
}

MBEAN_GET_KEY = mbeanGetKey;

try {
mbeanGetAttribute =
MethodHandles.publicLookup()
.findVirtual(
Class.forName("javax.management.DynamicMBean"),
"getAttribute",
MethodType.methodType(Object.class, String.class));
} catch (Exception e) {
mbeanGetAttribute = null;
}

MBEAN_GET_ATTRIBUTE = mbeanGetAttribute;

try {
mbeanClass = Class.forName("weblogic.management.WebLogicMBean");
} catch (Exception e) {
mbeanClass = null;
}

MBEAN_CLASS = mbeanClass;
}

public static class Request {
private static final Request NULL = new Request(null);

public final ServletRequest instance;

private Request(ServletRequest instance) {
this.instance = instance;
}

public static Request wrap(ServletRequest instance) {
return instance != null ? new Request(instance) : NULL;
}

public Context getContext() {
try {
return Context.wrap(
REQUEST_GET_CONTEXT != null ? REQUEST_GET_CONTEXT.invoke(instance) : null);
} catch (Throwable throwable) {
return Context.NULL;
}
}
}

public static class Context {
private static final Context NULL = new Context(null);

public final ServletContext instance;

private Context(ServletContext instance) {
this.instance = instance;
}

public static Context wrap(Object instance) {
return instance instanceof ServletContext ? new Context((ServletContext) instance) : NULL;
}

public Bean getBean() {
try {
return Bean.wrap(CONTEXT_GET_MBEAN != null ? CONTEXT_GET_MBEAN.invoke(instance) : null);
} catch (Throwable throwable) {
return Bean.NULL;
}
}

public Server getServer() {
try {
return Server.wrap(CONTEXT_GET_SERVER != null ? CONTEXT_GET_SERVER.invoke(instance) : null);
} catch (Throwable throwable) {
return Server.NULL;
}
}
}

public static class Server {
private static final Server NULL = new Server(null);

public final Object instance;

private Server(Object instance) {
this.instance = instance;
}

public static Server wrap(Object instance) {
return instance != null ? new Server(instance) : NULL;
}

public Bean getBean() {
try {
return Bean.wrap(SERVER_GET_MBEAN != null ? SERVER_GET_MBEAN.invoke(instance) : null);
} catch (Throwable throwable) {
return Bean.NULL;
}
}
}

public static class Bean {
private static final Bean NULL = new Bean(null);

public final Object instance;

private Bean(Object instance) {
this.instance = instance;
}

public static Bean wrap(Object instance) {
return instance != null
&& MBEAN_CLASS != null
&& MBEAN_CLASS.isAssignableFrom(instance.getClass())
? new Bean(instance)
: NULL;
}

public String getName() {
try {
Object key = MBEAN_GET_KEY != null ? MBEAN_GET_KEY.invoke(instance) : null;
return key != null ? key.toString() : null;
} catch (Throwable throwable) {
return null;
}
}

public Bean getParent() {
try {
return Bean.wrap(MBEAN_GET_PARENT != null ? MBEAN_GET_PARENT.invoke(instance) : null);
} catch (Throwable throwable) {
return Bean.NULL;
}
}

public Object getAttribute(String name) {
try {
return MBEAN_GET_ATTRIBUTE != null ? MBEAN_GET_ATTRIBUTE.invoke(instance, name) : null;
} catch (Throwable throwable) {
return null;
}
}
}
}
Loading