Commit 1fa05264 by Shwetha GS

ATLAS-1116 Performance monitoring of backend methods in API requests (shwethags)

parent 94a82722
......@@ -43,6 +43,14 @@
</layout>
</appender>
<appender name="METRICS" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="${atlas.log.dir}/metric.log"/>
<param name="Append" value="true"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %x %m%n"/>
</layout>
</appender>
<appender name="FAILED" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="${atlas.log.dir}/failed.log"/>
<param name="Append" value="true"/>
......@@ -56,22 +64,6 @@
<appender-ref ref="FILE"/>
</logger>
<!-- uncomment this block to generate performance traces
<appender name="perf_appender" class="org.apache.log4j.DailyRollingFileAppender">
<param name="file" value="${atlas.log.dir}/atlas_perf.log" />
<param name="datePattern" value="'.'yyyy-MM-dd" />
<param name="append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d|%t|%m%n" />
</layout>
</appender>
<logger name="org.apache.atlas.perf" additivity="false">
<level value="debug" />
<appender-ref ref="perf_appender" />
</logger>
-->
<logger name="com.thinkaurelius.titan" additivity="false">
<level value="warn"/>
<appender-ref ref="FILE"/>
......@@ -88,6 +80,11 @@
<appender-ref ref="AUDIT"/>
</logger>
<logger name="METRICS" additivity="false">
<level value="debug"/>
<appender-ref ref="METRICS"/>
</logger>
<logger name="FAILED" additivity="false">
<level value="info"/>
<appender-ref ref="AUDIT"/>
......
......@@ -284,3 +284,16 @@ atlas.webserver.keepalivetimesecs=60
# Queue size for the requests(when max threads are busy) for the atlas web server
atlas.webserver.queuesize=100
</verbatim>
---+++ Recording performance metrics
Atlas package should be built with '-P perf' to instrument atlas code to collect metrics. The metrics will be recorded in
<atlas.log.dir>/metric.log, with one log line per API call. The metrics contain the number of times the instrumented methods
are called and the total time spent in the instrumented method. Logging to metric.log is controlled through log4j configuration
in atlas-log4j.xml. When the atlas code is instrumented, to disable logging to metric.log at runtime, set log level of METRICS logger to info level:
<verbatim>
<logger name="METRICS" additivity="false">
<level value="info"/>
<appender-ref ref="METRICS"/>
</logger>
</verbatim>
......@@ -18,6 +18,10 @@ mvn clean package -Pdist
</verbatim>
NOTE:
1. Use option '-DskipTests' to skip running unit and integration tests
2. Use option '-P perf' to instrument atlas to collect performance metrics
To build a distribution that configures Atlas for external HBase and Solr, build with the external-hbase-solr profile.
<verbatim>
......
......@@ -491,9 +491,23 @@
<entity.repository.impl>org.apache.atlas.repository.audit.InMemoryEntityAuditRepository</entity.repository.impl>
<graphdb.backend.impl>org.apache.atlas.repository.graphdb.titan0.Titan0GraphDatabase</graphdb.backend.impl>
<atlas.surefire.options></atlas.surefire.options>
<aspectj.runtime.version>1.8.7</aspectj.runtime.version>
<aspectj.skip>true</aspectj.skip>
</properties>
<profiles>
<!-- Turn on this profile to instrument atlas server to collect performance metrics -->
<profile>
<id>perf</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<aspectj.skip>false</aspectj.skip>
</properties>
</profile>
<!-- Turning on this profile affects only tests and does not affect packaging -->
<profile>
<id>distributed</id>
......@@ -618,6 +632,18 @@
<dependencyManagement>
<dependencies>
<!-- AOP dependencies. -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.runtime.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.runtime.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jsp</artifactId>
......@@ -1631,6 +1657,12 @@
<excludeGroupIds>org.restlet.jee</excludeGroupIds>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
</plugin>
</plugins>
</pluginManagement>
......
......@@ -9,6 +9,7 @@ ATLAS-1060 Add composite indexes for exact match performance improvements for al
ATLAS-1127 Modify creation and modification timestamps to Date instead of Long(sumasai)
ALL CHANGES:
ATLAS-1116 Performance monitoring of backend methods in API requests (shwethags)
ATLAS-1310 attempt LDAP authentication only when enabled (mneethiraj)
ATLAS-1309 updated HBase model with addition of column-family and column entity-defs (mneethiraj)
ATLAS-916 Return System Attributes in get entity definition (svimal2106)
......
......@@ -219,6 +219,47 @@
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<complianceLevel>1.7</complianceLevel>
<includes>
<include>**/*.java</include>
<include>**/*.aj</include>
</includes>
<XaddSerialVersionUID>true</XaddSerialVersionUID>
<showWeaveInfo>true</showWeaveInfo>
<aspectLibraries>
<aspectLibrary>
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-server-api</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<id>compile_with_aspectj</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.runtime.version}</version>
</dependency>
<dependency>
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-server-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
......@@ -17,8 +17,9 @@
*/
package org.apache.atlas.repository.graph;
import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.AtlasException;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.typesystem.ITypedInstance;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.types.AttributeInfo;
......@@ -49,6 +50,7 @@ public class FullTextMapper {
instanceCache = new HashMap<>();
}
@Monitored
public String mapRecursive(AtlasVertex instanceVertex, boolean followReferences) throws AtlasException {
String guid = GraphHelper.getIdFromVertex(instanceVertex);
ITypedReferenceableInstance typedReference;
......
......@@ -18,20 +18,13 @@
package org.apache.atlas.repository.graph;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.UUID;
import java.util.Date;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasException;
import org.apache.atlas.RequestContext;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.RepositoryException;
import org.apache.atlas.repository.graphdb.AtlasEdge;
......@@ -65,9 +58,15 @@ import org.codehaus.jettison.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.UUID;
/**
* Utility class for graph operations.
......@@ -138,6 +137,7 @@ public final class GraphHelper {
return vertexWithIdentity;
}
@Monitored
public AtlasVertex createVertexWithoutIdentity(String typeName, Id typedInstanceId, Set<String> superTypeNames) {
LOG.debug("Creating AtlasVertex for type {} id {}", typeName,
typedInstanceId != null ? typedInstanceId._getId() : null);
......@@ -165,6 +165,7 @@ public final class GraphHelper {
return vertexWithoutIdentity;
}
@Monitored
private AtlasEdge addEdge(AtlasVertex fromVertex, AtlasVertex toVertex, String edgeLabel) {
LOG.debug("Adding edge for {} -> label {} -> {}", string(fromVertex), edgeLabel, string(toVertex));
AtlasEdge edge = graph.addEdge(fromVertex, toVertex, edgeLabel);
......@@ -216,7 +217,7 @@ public final class GraphHelper {
return null;
}
@Monitored
public AtlasEdge getEdgeByEdgeId(AtlasVertex outVertex, String edgeLabel, String edgeId) {
if (edgeId == null) {
return null;
......@@ -242,6 +243,7 @@ public final class GraphHelper {
* @return AtlasVertex with the given property keys
* @throws EntityNotFoundException
*/
@Monitored
public AtlasVertex findVertex(Object... args) throws EntityNotFoundException {
StringBuilder condition = new StringBuilder();
AtlasGraphQuery query = graph.query();
......@@ -268,6 +270,7 @@ public final class GraphHelper {
//In some cases of parallel APIs, the edge is added, but get edge by label doesn't return the edge. ATLAS-1104
//So traversing all the edges
@Monitored
public Iterator<AtlasEdge> getAdjacentEdgesByLabel(AtlasVertex instanceVertex, AtlasEdgeDirection direction, final String edgeLabel) {
LOG.debug("Finding edges for {} with label {}", string(instanceVertex), edgeLabel);
if(instanceVertex != null && edgeLabel != null) {
......@@ -316,6 +319,7 @@ public final class GraphHelper {
* @param edgeLabel
* @return
*/
@Monitored
public AtlasEdge getEdgeForLabel(AtlasVertex vertex, String edgeLabel) {
Iterator<AtlasEdge> iterator = getAdjacentEdgesByLabel(vertex, AtlasEdgeDirection.OUT, edgeLabel);
AtlasEdge latestDeletedEdge = null;
......@@ -340,6 +344,7 @@ public final class GraphHelper {
return latestDeletedEdge;
}
@Monitored
public static String vertexString(final AtlasVertex vertex) {
StringBuilder properties = new StringBuilder();
for (String propertyKey : vertex.getPropertyKeys()) {
......@@ -350,11 +355,13 @@ public final class GraphHelper {
return "v[" + vertex.getIdForDisplay() + "], Properties[" + properties + "]";
}
@Monitored
public static String edgeString(final AtlasEdge edge) {
return "e[" + edge.getLabel() + "], [" + edge.getOutVertex() + " -> " + edge.getLabel() + " -> "
+ edge.getInVertex() + "]";
}
@Monitored
public static <T extends AtlasElement> void setProperty(T element, String propertyName, Object value) {
String elementStr = string(element);
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
......@@ -383,6 +390,7 @@ public final class GraphHelper {
* @param clazz
* @return
*/
@Monitored
public static <T> T getSingleValuedProperty(AtlasElement element, String propertyName, Class<T> clazz) {
String elementStr = string(element);
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
......@@ -392,6 +400,7 @@ public final class GraphHelper {
}
@Monitored
public static Object getProperty(AtlasVertex<?,?> vertex, String propertyName) {
String elementStr = string(vertex);
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
......@@ -403,9 +412,9 @@ public final class GraphHelper {
else {
return vertex.getProperty(actualPropertyName, Object.class);
}
}
@Monitored
public static Object getProperty(AtlasEdge<?,?> edge, String propertyName) {
String elementStr = string(edge);
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
......@@ -429,6 +438,7 @@ public final class GraphHelper {
* @param propertyName
* @param value
*/
@Monitored
public static void addProperty(AtlasVertex vertex, String propertyName, Object value) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
LOG.debug("Adding property {} = \"{}\" to vertex {}", actualPropertyName, value, string(vertex));
......@@ -440,6 +450,7 @@ public final class GraphHelper {
*
* @param edge
*/
@Monitored
public void removeEdge(AtlasEdge edge) {
String edgeString = string(edge);
LOG.debug("Removing {}", edgeString);
......@@ -450,8 +461,9 @@ public final class GraphHelper {
/**
* Remove the specified AtlasVertex from the graph.
*
* @param AtlasVertex
* @param vertex
*/
@Monitored
public void removeVertex(AtlasVertex vertex) {
String vertexString = string(vertex);
LOG.debug("Removing {}", vertexString);
......@@ -746,6 +758,7 @@ public final class GraphHelper {
}
@Monitored
public static void setArrayElementsProperty(IDataType elementType, AtlasVertex instanceVertex, String propertyName, List<Object> values) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if(GraphHelper.isReference(elementType)) {
......@@ -756,6 +769,7 @@ public final class GraphHelper {
}
}
@Monitored
public static void setMapValueProperty(IDataType elementType, AtlasVertex instanceVertex, String propertyName, Object value) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if(GraphHelper.isReference(elementType)) {
......@@ -766,6 +780,7 @@ public final class GraphHelper {
}
}
@Monitored
public static Object getMapValueProperty(IDataType elementType, AtlasVertex instanceVertex, String propertyName) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if(GraphHelper.isReference(elementType)) {
......@@ -776,6 +791,7 @@ public final class GraphHelper {
}
}
@Monitored
public static List<Object> getArrayElementsProperty(IDataType elementType, AtlasVertex instanceVertex, String propertyName) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if(GraphHelper.isReference(elementType)) {
......@@ -918,7 +934,4 @@ public final class GraphHelper {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
return instanceVertex.getListProperty(actualPropertyName);
}
}
......@@ -17,17 +17,9 @@
*/
package org.apache.atlas.repository.graph;
import static org.apache.atlas.repository.graph.GraphHelper.string;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.inject.Singleton;
import org.apache.atlas.AtlasException;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.graphdb.AtlasEdge;
import org.apache.atlas.repository.graphdb.AtlasEdgeDirection;
......@@ -51,7 +43,15 @@ import org.apache.atlas.typesystem.types.TypeSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Singleton;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.atlas.repository.graph.GraphHelper.string;
@Singleton
public final class GraphToTypedInstanceMapper {
......@@ -66,6 +66,7 @@ public final class GraphToTypedInstanceMapper {
this.graph = graph;
}
@Monitored
public ITypedReferenceableInstance mapGraphToTypedInstance(String guid, AtlasVertex instanceVertex)
throws AtlasException {
......@@ -95,6 +96,7 @@ public final class GraphToTypedInstanceMapper {
return typedInstance;
}
@Monitored
private void mapVertexToInstanceTraits(AtlasVertex instanceVertex, ITypedReferenceableInstance typedInstance,
List<String> traits) throws AtlasException {
for (String traitName : traits) {
......@@ -104,6 +106,7 @@ public final class GraphToTypedInstanceMapper {
}
}
@Monitored
public void mapVertexToInstance(AtlasVertex instanceVertex, ITypedInstance typedInstance,
Map<String, AttributeInfo> fields) throws AtlasException {
......
......@@ -17,21 +17,10 @@
*/
package org.apache.atlas.repository.graph;
import static org.apache.atlas.repository.graph.GraphHelper.string;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.inject.Inject;
import org.apache.atlas.AtlasException;
import org.apache.atlas.RequestContext;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.RepositoryException;
import org.apache.atlas.repository.graphdb.AtlasEdge;
......@@ -59,7 +48,18 @@ import org.apache.atlas.utils.MD5Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.apache.atlas.repository.graph.GraphHelper.string;
public final class TypedInstanceToGraphMapper {
......@@ -85,9 +85,9 @@ public final class TypedInstanceToGraphMapper {
UPDATE_FULL
}
@Monitored
void mapTypedInstanceToGraph(Operation operation, ITypedReferenceableInstance... typedInstances)
throws AtlasException {
RequestContext requestContext = RequestContext.get();
for (ITypedReferenceableInstance typedInstance : typedInstances) {
LOG.debug("Adding/updating entity {}", typedInstance);
......@@ -150,6 +150,7 @@ public final class TypedInstanceToGraphMapper {
return guids;
}
@Monitored
private String addOrUpdateAttributesAndTraits(Operation operation, ITypedReferenceableInstance typedInstance)
throws AtlasException {
LOG.debug("Adding/Updating typed instance {}", typedInstance.toShortString());
......@@ -235,6 +236,7 @@ public final class TypedInstanceToGraphMapper {
}
}
@Monitored
private TypeUtils.Pair<List<ITypedReferenceableInstance>, List<ITypedReferenceableInstance>> createVerticesAndDiscoverInstances(
Collection<IReferenceableInstance> instances) throws AtlasException {
......
......@@ -142,7 +142,7 @@ public class AtlasGraphUtilsV1 {
return returnType.cast(property);
}
private static <T extends AtlasElement> String toString(T element) {
private static String toString(AtlasElement element) {
if (element instanceof AtlasVertex) {
return toString((AtlasVertex) element);
} else if (element instanceof AtlasEdge) {
......
......@@ -60,6 +60,58 @@
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-client</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<complianceLevel>1.7</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<forceAjcCompile>true</forceAjcCompile>
<includes>
<include>**/*.java</include>
<include>**/*.aj</include>
</includes>
</configuration>
<executions>
<execution>
<id>compile_with_aspectj</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<aspectDirectory>src/main/java</aspectDirectory>
</configuration>
</execution>
<execution>
<id>test-compile_with_aspectj</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.runtime.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.runtime.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
......@@ -18,6 +18,7 @@
package org.apache.atlas;
import org.apache.atlas.metrics.Metrics;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.persistence.Id;
import org.apache.atlas.typesystem.types.ClassType;
......@@ -45,6 +46,7 @@ public class RequestContext {
private long requestTime;
TypeSystem typeSystem = TypeSystem.getInstance();
private Metrics metrics = new Metrics();
private RequestContext() {
}
......@@ -124,4 +126,8 @@ public class RequestContext {
public boolean isDeletedEntity(String entityGuid) {
return deletedEntityIds.contains(entityGuid);
}
public static Metrics getMetrics() {
return get().metrics;
}
}
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.atlas.aspect;
import org.apache.atlas.RequestContext;
import org.apache.atlas.metrics.Metrics;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
@Aspect
public class AtlasAspect {
public static final Logger LOG = LoggerFactory.getLogger(AtlasAspect.class);
@Around("@annotation(org.apache.atlas.aspect.Monitored) && execution(* *(..))")
public Object collectMetricsForMonitored(ProceedingJoinPoint joinPoint) throws Throwable {
Signature methodSign = joinPoint.getSignature();
Metrics metrics = RequestContext.getMetrics();
String metricName = methodSign.getDeclaringType().getSimpleName() + "." + methodSign.getName();
long start = System.currentTimeMillis();
try {
Object response = joinPoint.proceed();
return response;
} finally {
metrics.record(metricName, (System.currentTimeMillis() - start));
}
}
@Around("@annotation(org.apache.atlas.aspect.Loggable) && execution(* *(..))")
public Object logAroundLoggable(ProceedingJoinPoint joinPoint) throws Throwable {
Signature methodSign = joinPoint.getSignature();
String methodName = methodSign.getDeclaringType().getSimpleName() + "." + methodSign.getName();
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("==> %s(%s)", methodName, joinPoint.getArgs()));
}
Object response = joinPoint.proceed();
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("<== %s(%s): %s", methodName, joinPoint.getArgs(),
response instanceof List ? ((List)response).size() : response));
}
return response;
}
}
\ No newline at end of file
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.atlas.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
}
\ No newline at end of file
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.atlas.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Monitored {
}
\ No newline at end of file
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.atlas.metrics;
import java.util.LinkedHashMap;
import java.util.Map;
public class Metrics {
public static class Counters {
private short invocations = 0;
private long totalTimeMSecs = 0;
@Override
public String toString() {
return "[count=" + invocations + ", totalTimeMSec=" + totalTimeMSecs + "]";
}
public short getInvocations() {
return invocations;
}
public long getTotalTimeMSecs() {
return totalTimeMSecs;
}
}
Map<String, Counters> countersMap = new LinkedHashMap<>();
public void record(String name, long timeMsecs) {
Counters counter = countersMap.get(name);
if (counter == null) {
counter = new Counters();
countersMap.put(name, counter);
}
counter.invocations++;
counter.totalTimeMSecs += timeMsecs;
}
@Override
public String toString() {
return countersMap.toString();
}
public boolean isEmpty() {
return countersMap.isEmpty();
}
public Counters getCounters(String name) {
return countersMap.get(name);
}
}
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.atlas;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.metrics.Metrics;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
public class MonitoredAspectTest {
@Monitored
public void monitoredMethod() throws InterruptedException {
Thread.sleep(1);
}
@Test
public void testMonitoredAspect() throws Exception {
RequestContext.clear();
monitoredMethod();
Metrics metrics = RequestContext.getMetrics();
Metrics.Counters counters = metrics.getCounters("MonitoredAspectTest.monitoredMethod");
assertNotNull(counters);
assertEquals(counters.getInvocations(), 1);
assertTrue(counters.getTotalTimeMSecs() > 0);
}
}
......@@ -41,22 +41,6 @@
<appender-ref ref="console"/>
</logger>
<!-- uncomment this block to generate performance traces
<appender name="perf_appender" class="org.apache.log4j.DailyRollingFileAppender">
<param name="file" value="${atlas.log.dir}/atlas_perf.log" />
<param name="datePattern" value="'.'yyyy-MM-dd" />
<param name="append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d|%t|%m%n" />
</layout>
</appender>
<logger name="org.apache.atlas.perf" additivity="false">
<level value="debug" />
<appender-ref ref="perf_appender" />
</logger>
-->
<appender name="FAILED" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="${atlas.log.dir}/failed.log"/>
<param name="Append" value="true"/>
......
......@@ -384,6 +384,16 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-server-api</artifactId>
</dependency>
</dependencies>
<build>
......@@ -607,6 +617,47 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<complianceLevel>1.7</complianceLevel>
<includes>
<include>**/*.java</include>
<include>**/*.aj</include>
</includes>
<XaddSerialVersionUID>true</XaddSerialVersionUID>
<showWeaveInfo>true</showWeaveInfo>
<aspectLibraries>
<aspectLibrary>
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-server-api</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<id>compile_with_aspectj</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.runtime.version}</version>
</dependency>
<dependency>
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-server-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
......@@ -21,6 +21,7 @@ package org.apache.atlas.web.filters;
import com.google.inject.Singleton;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.RequestContext;
import org.apache.atlas.metrics.Metrics;
import org.apache.atlas.web.util.DateTimeHelper;
import org.apache.atlas.web.util.Servlets;
import org.slf4j.Logger;
......@@ -47,6 +48,7 @@ public class AuditFilter implements Filter {
private static final Logger AUDIT_LOG = LoggerFactory.getLogger("AUDIT");
private static final Logger LOG = LoggerFactory.getLogger(AuditFilter.class);
private static final Logger METRICS_LOG = LoggerFactory.getLogger("METRICS");
@Override
public void init(FilterConfig filterConfig) throws ServletException {
......@@ -73,6 +75,7 @@ public class AuditFilter implements Filter {
// put the request id into the response so users can trace logs for this request
((HttpServletResponse) response).setHeader(AtlasClient.REQUEST_ID, requestId);
currentThread.setName(oldName);
recordMetrics();
RequestContext.clear();
}
}
......@@ -103,6 +106,14 @@ public class AuditFilter implements Filter {
whatAddrs, whenISO9601);
}
public static void recordMetrics() {
//record metrics
Metrics requestMetrics = RequestContext.getMetrics();
if (!requestMetrics.isEmpty()) {
METRICS_LOG.info("{}", requestMetrics);
}
}
@Override
public void destroy() {
// do nothing
......
......@@ -18,19 +18,9 @@
package org.apache.atlas.web.resources;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.google.inject.Inject;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
import org.apache.atlas.web.service.ServiceState;
......@@ -45,7 +35,16 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import com.google.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* Jersey Resource for admin operations.
......@@ -74,17 +73,11 @@ public class AdminResource {
*
* @return json representing the thread stack dump.
*/
@Monitored
@GET
@Path("stack")
@Produces(MediaType.TEXT_PLAIN)
public String getThreadDump() {
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "AdminResource.getThreadDump()");
}
ThreadGroup topThreadGroup = Thread.currentThread().getThreadGroup();
while (topThreadGroup.getParent() != null) {
......@@ -101,9 +94,6 @@ public class AdminResource {
builder.append(stackTrace);
}
return builder.toString();
} finally {
AtlasPerfTracer.log(perf);
}
}
/**
......@@ -111,17 +101,11 @@ public class AdminResource {
*
* @return json representing the version.
*/
@Monitored
@GET
@Path("version")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getVersion() {
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "AdminResource.getVersion()");
}
if (version == null) {
try {
PropertiesConfiguration configProperties = new PropertiesConfiguration("atlas-buildinfo.properties");
......@@ -141,22 +125,13 @@ public class AdminResource {
}
return version;
} finally {
AtlasPerfTracer.log(perf);
}
}
@Monitored
@GET
@Path("status")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getStatus() {
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "AdminResource.getStatus()");
}
JSONObject responseData = new JSONObject();
try {
responseData.put(AtlasClient.STATUS, serviceState.getState().toString());
......@@ -165,23 +140,16 @@ public class AdminResource {
} catch (JSONException e) {
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
} finally {
AtlasPerfTracer.log(perf);
}
}
@Monitored
@GET
@Path("session")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getUserProfile() {
JSONObject responseData = new JSONObject();
Boolean enableTaxonomy = null;
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "AdminResource.getUserProfile()");
}
PropertiesConfiguration configProperties = new PropertiesConfiguration("atlas-application.properties");
enableTaxonomy = new Boolean(configProperties.getString(isTaxonomyEnabled, "false"));
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
......@@ -208,8 +176,6 @@ public class AdminResource {
return response;
} catch (JSONException | ConfigurationException e) {
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
}
......@@ -19,6 +19,7 @@
package org.apache.atlas.web.resources;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.discovery.DiscoveryException;
import org.apache.atlas.discovery.LineageService;
import org.apache.atlas.typesystem.exception.EntityNotFoundException;
......@@ -68,6 +69,7 @@ public class DataSetLineageResource {
*
* @param tableName table name
*/
@Monitored
@GET
@Path("table/{tableName}/inputs/graph")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -75,12 +77,7 @@ public class DataSetLineageResource {
public Response inputsGraph(@Context HttpServletRequest request, @PathParam("tableName") String tableName) {
LOG.info("Fetching lineage inputs graph for tableName={}", tableName);
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataSetLineageResource.inputsGraph(" + tableName + ")");
}
final String jsonResult = lineageService.getInputsGraph(tableName);
JSONObject response = new JSONObject();
......@@ -98,8 +95,6 @@ public class DataSetLineageResource {
} catch (Throwable e) {
LOG.error("Unable to get lineage inputs graph for table {}", tableName, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -108,6 +103,7 @@ public class DataSetLineageResource {
*
* @param tableName table name
*/
@Monitored
@GET
@Path("table/{tableName}/outputs/graph")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -115,12 +111,7 @@ public class DataSetLineageResource {
public Response outputsGraph(@Context HttpServletRequest request, @PathParam("tableName") String tableName) {
LOG.info("Fetching lineage outputs graph for tableName={}", tableName);
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataSetLineageResource.outputsGraph(" + tableName + ")");
}
final String jsonResult = lineageService.getOutputsGraph(tableName);
JSONObject response = new JSONObject();
......@@ -138,8 +129,6 @@ public class DataSetLineageResource {
} catch (Throwable e) {
LOG.error("Unable to get lineage outputs graph for table {}", tableName, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -148,6 +137,7 @@ public class DataSetLineageResource {
*
* @param tableName table name
*/
@Monitored
@GET
@Path("table/{tableName}/schema")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -155,12 +145,7 @@ public class DataSetLineageResource {
public Response schema(@Context HttpServletRequest request, @PathParam("tableName") String tableName) {
LOG.info("Fetching schema for tableName={}", tableName);
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataSetLineageResource.schema(" + tableName + ")");
}
final String jsonResult = lineageService.getSchema(tableName);
JSONObject response = new JSONObject();
......@@ -178,8 +163,6 @@ public class DataSetLineageResource {
} catch (Throwable e) {
LOG.error("Unable to get schema for table {}", tableName, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
}
......@@ -24,6 +24,7 @@ import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasConstants;
import org.apache.atlas.AtlasException;
import org.apache.atlas.EntityAuditEvent;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.services.MetadataService;
import org.apache.atlas.typesystem.IStruct;
import org.apache.atlas.typesystem.Referenceable;
......@@ -33,8 +34,8 @@ import org.apache.atlas.typesystem.exception.TraitNotFoundException;
import org.apache.atlas.typesystem.exception.TypeNotFoundException;
import org.apache.atlas.typesystem.json.InstanceSerialization;
import org.apache.atlas.typesystem.types.ValueConversionException;
import org.apache.atlas.utils.ParamChecker;
import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.atlas.utils.ParamChecker;
import org.apache.atlas.web.util.Servlets;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jettison.json.JSONArray;
......@@ -104,18 +105,13 @@ public class EntityResource {
* The body contains the JSONArray of entity json. The service takes care of de-duping the entities based on any
* unique attribute for the give type.
*/
@Monitored
@POST
@Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response submit(@Context HttpServletRequest request) {
String entityJson = null;
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.submit()");
}
String entities = Servlets.getRequestPayload(request);
//Handle backward compatibility - if entities is not JSONArray, convert to JSONArray
......@@ -151,8 +147,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to persist entity instance entityDef={}", entityJson, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -190,18 +184,13 @@ public class EntityResource {
* Adds/Updates given entities identified by its GUID or unique attribute
* @return response payload as json
*/
@Monitored
@PUT
@Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response updateEntities(@Context HttpServletRequest request) {
String entityJson = null;
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.updateEntities()");
}
final String entities = Servlets.getRequestPayload(request);
entityJson = AtlasClient.toString(new JSONArray(entities));
......@@ -224,8 +213,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to persist entity instance entityDef={}", entityJson, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -258,6 +245,7 @@ public class EntityResource {
* The body contains the JSONArray of entity json. The service takes care of de-duping the entities based on any
* unique attribute for the give type.
*/
@Monitored
@POST
@Path("qualifiedName")
@Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
......@@ -265,14 +253,8 @@ public class EntityResource {
public Response updateByUniqueAttribute(@QueryParam("type") String entityType,
@QueryParam("property") String attribute,
@QueryParam("value") String value, @Context HttpServletRequest request) {
String entityJson = null;
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.updateByUniqueAttribute()");
}
entityJson = Servlets.getRequestPayload(request);
LOG.info("Partially updating entity by unique attribute {} {} {} {} ", entityType, attribute, value, entityJson);
......@@ -301,8 +283,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to partially update entity {} {} " + entityType + ":" + attribute + "." + value, entityJson, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -321,22 +301,14 @@ public class EntityResource {
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response updateEntityByGuid(@PathParam("guid") String guid, @QueryParam("property") String attribute,
@Context HttpServletRequest request) {
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.updateEntityByGuid()");
}
if (StringUtils.isEmpty(attribute)) {
return updateEntityPartialByGuid(guid, request);
} else {
return updateEntityAttributeByGuid(guid, attribute, request);
}
} finally {
AtlasPerfTracer.log(perf);
}
}
@Monitored
private Response updateEntityPartialByGuid(String guid, HttpServletRequest request) {
String entityJson = null;
try {
......@@ -374,6 +346,7 @@ public class EntityResource {
* @postbody property's value
* @return response payload as json
*/
@Monitored
private Response updateEntityAttributeByGuid(String guid, String property, HttpServletRequest request) {
String value = null;
try {
......@@ -411,19 +384,14 @@ public class EntityResource {
* @param value the unique attribute value used to identify the entity
* @return response payload as json - including guids of entities(including composite references from that entity) that were deleted
*/
@Monitored
@DELETE
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response deleteEntities(@QueryParam("guid") List<String> guids,
@QueryParam("type") String entityType,
@QueryParam("property") String attribute,
@QueryParam("value") String value) {
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.deleteEntities()");
}
AtlasClient.EntityResult entityResult;
if (guids != null && !guids.isEmpty()) {
LOG.info("Deleting entities {}", guids);
......@@ -448,8 +416,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to delete entities {} {} {} {} ", guids, entityType, attribute, value, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -458,16 +424,12 @@ public class EntityResource {
*
* @param guid GUID for the entity
*/
@Monitored
@GET
@Path("{guid}")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getEntityDefinition(@PathParam("guid") String guid) {
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.getEntityDefinition()");
}
LOG.debug("Fetching entity definition for guid={} ", guid);
guid = ParamChecker.notEmpty(guid, "guid cannot be null");
final String entityDefinition = metadataService.getEntityDefinitionJson(guid);
......@@ -495,8 +457,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to get instance definition for GUID {}", guid, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -505,6 +465,7 @@ public class EntityResource {
*
* @param entityType name of a type which is unique
*/
@Monitored
public Response getEntityListByType(String entityType) {
try {
Preconditions.checkNotNull(entityType, "Entity type cannot be null");
......@@ -537,12 +498,6 @@ public class EntityResource {
public Response getEntity(@QueryParam("type") String entityType,
@QueryParam("property") String attribute,
@QueryParam("value") String value) {
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.getEntity(" + entityType + ", " + attribute + ", " + value + ")");
}
if (StringUtils.isEmpty(attribute)) {
//List API
return getEntityListByType(entityType);
......@@ -550,9 +505,6 @@ public class EntityResource {
//Get entity by unique attribute
return getEntityDefinitionByAttribute(entityType, attribute, value);
}
} finally {
AtlasPerfTracer.log(perf);
}
}
/**
......@@ -562,6 +514,7 @@ public class EntityResource {
* @param attribute
* @param value
*/
@Monitored
public Response getEntityDefinitionByAttribute(String entityType, String attribute, String value) {
try {
LOG.debug("Fetching entity definition for type={}, qualified name={}", entityType, value);
......@@ -606,16 +559,12 @@ public class EntityResource {
* @param guid globally unique identifier for the entity
* @return a list of trait names for the given entity guid
*/
@Monitored
@GET
@Path("{guid}/traits")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getTraitNames(@PathParam("guid") String guid) {
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.getTraitNames(" + guid + ")");
}
LOG.debug("Fetching trait names for entity={}", guid);
final List<String> traitNames = metadataService.getTraitNames(guid);
......@@ -634,8 +583,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to get trait names for entity {}", guid, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -643,15 +590,12 @@ public class EntityResource {
* Fetches the trait definitions of all the traits associated to the given entity
* @param guid globally unique identifier for the entity
*/
@Monitored
@GET
@Path("{guid}/traitDefinitions")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getTraitDefinitionsForEntity(@PathParam("guid") String guid){
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.getTraitDefinitionsForEntity(" + guid + ")");
}
LOG.debug("Fetching all trait definitions for entity={}", guid);
final String entityDefinition = metadataService.getEntityDefinitionJson(guid);
......@@ -677,10 +621,7 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to get trait definitions for entity {}", guid, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
/**
......@@ -689,15 +630,12 @@ public class EntityResource {
* @param guid globally unique identifier for the entity
* @param traitName name of the trait
*/
@Monitored
@GET
@Path("{guid}/traitDefinitions/{traitName}")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getTraitDefinitionForEntity(@PathParam("guid") String guid, @PathParam("traitName") String traitName){
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.getTraitDefinitionForEntity(" + guid + ", " + traitName + ")");
}
LOG.debug("Fetching trait definition for entity {} and trait name {}", guid, traitName);
final IStruct traitDefinition = metadataService.getTraitDefinition(guid, traitName);
......@@ -716,8 +654,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to get trait definition for entity {} and trait {}", guid, traitName, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -726,18 +662,14 @@ public class EntityResource {
*
* @param guid globally unique identifier for the entity
*/
@Monitored
@POST
@Path("{guid}/traits")
@Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response addTrait(@Context HttpServletRequest request, @PathParam("guid") final String guid) {
String traitDefinition = null;
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.addTrait(" + guid + ")");
}
traitDefinition = Servlets.getRequestPayload(request);
LOG.info("Adding trait={} for entity={} ", traitDefinition, guid);
metadataService.addTrait(guid, traitDefinition);
......@@ -759,8 +691,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to add trait for entity={} traitDef={}", guid, traitDefinition, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -770,6 +700,7 @@ public class EntityResource {
* @param guid globally unique identifier for the entity
* @param traitName name of the trait
*/
@Monitored
@DELETE
@Path("{guid}/traits/{traitName}")
@Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
......@@ -777,12 +708,7 @@ public class EntityResource {
public Response deleteTrait(@Context HttpServletRequest request, @PathParam("guid") String guid,
@PathParam(TRAIT_NAME) String traitName) {
LOG.info("Deleting trait={} from entity={} ", traitName, guid);
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.deleteTrait(" + guid + ", " + traitName + ")");
}
metadataService.deleteTrait(guid, traitName);
JSONObject response = new JSONObject();
......@@ -802,8 +728,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to delete trait name={} for entity={}", traitName, guid, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -817,6 +741,7 @@ public class EntityResource {
* @param count number of events required
* @return
*/
@Monitored
@GET
@Path("{guid}/audit")
@Produces(Servlets.JSON_MEDIA_TYPE)
......@@ -824,12 +749,7 @@ public class EntityResource {
@QueryParam("count") @DefaultValue("100") short count) {
LOG.debug("Audit events request for entity {}, start key {}, number of results required {}", guid, startKey,
count);
AtlasPerfTracer perf = null;
try {
if(AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityResource.getAuditEvents(" + guid + ", " + startKey + ", " + count + ")");
}
List<EntityAuditEvent> events = metadataService.getAuditEvents(guid, startKey, count);
JSONObject response = new JSONObject();
......@@ -842,8 +762,6 @@ public class EntityResource {
} catch (Throwable e) {
LOG.error("Unable to get audit events for entity guid={} startKey={}", guid, startKey, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......
......@@ -19,6 +19,7 @@
package org.apache.atlas.web.resources;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.discovery.DiscoveryException;
import org.apache.atlas.discovery.LineageService;
import org.apache.atlas.typesystem.exception.EntityNotFoundException;
......@@ -63,6 +64,7 @@ public class LineageResource {
* @param guid dataset entity id
* @return
*/
@Monitored
@GET
@Path("{guid}/inputs/graph")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -70,12 +72,7 @@ public class LineageResource {
public Response inputsGraph(@PathParam("guid") String guid) {
LOG.info("Fetching lineage inputs graph for guid={}", guid);
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "LineageResource.inputsGraph(" + guid + ")");
}
final String jsonResult = lineageService.getInputsGraphForEntity(guid);
JSONObject response = new JSONObject();
......@@ -92,8 +89,6 @@ public class LineageResource {
} catch (Throwable e) {
LOG.error("Unable to get lineage inputs graph for entity guid={}", guid, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -102,6 +97,7 @@ public class LineageResource {
*
* @param guid dataset entity id
*/
@Monitored
@GET
@Path("{guid}/outputs/graph")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -109,12 +105,7 @@ public class LineageResource {
public Response outputsGraph(@PathParam("guid") String guid) {
LOG.info("Fetching lineage outputs graph for entity guid={}", guid);
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "LineageResource.outputsGraph(" + guid + ")");
}
final String jsonResult = lineageService.getOutputsGraphForEntity(guid);
JSONObject response = new JSONObject();
......@@ -131,8 +122,6 @@ public class LineageResource {
} catch (Throwable e) {
LOG.error("Unable to get lineage outputs graph for entity guid={}", guid, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -141,6 +130,7 @@ public class LineageResource {
*
* @param guid dataset entity id
*/
@Monitored
@GET
@Path("{guid}/schema")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -148,12 +138,7 @@ public class LineageResource {
public Response schema(@PathParam("guid") String guid) {
LOG.info("Fetching schema for entity guid={}", guid);
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "LineageResource.schema(" + guid + ")");
}
final String jsonResult = lineageService.getSchemaForEntity(guid);
JSONObject response = new JSONObject();
......@@ -173,8 +158,6 @@ public class LineageResource {
} catch (Throwable e) {
LOG.error("Unable to get schema for entity={}", guid, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
}
......@@ -21,6 +21,7 @@ package org.apache.atlas.web.resources;
import com.google.common.base.Preconditions;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasConfiguration;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.classification.InterfaceAudience;
import org.apache.atlas.discovery.DiscoveryException;
import org.apache.atlas.discovery.DiscoveryService;
......@@ -82,6 +83,7 @@ public class MetadataDiscoveryResource {
* @param offset offset to the results returned, used for pagination. offset >= 0. -1 maps to offset 0
* @return JSON representing the type and results.
*/
@Monitored
@GET
@Path("search")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -89,11 +91,6 @@ public class MetadataDiscoveryResource {
public Response search(@QueryParam("query") String query,
@DefaultValue(LIMIT_OFFSET_DEFAULT) @QueryParam("limit") int limit,
@DefaultValue(LIMIT_OFFSET_DEFAULT) @QueryParam("offset") int offset) {
AtlasPerfTracer perf = null;
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "MetadataDiscoveryResource.search(" + query + ", " + limit + ", " + offset + ")");
}
boolean dslQueryFailed = false;
Response response = null;
try {
......@@ -109,7 +106,6 @@ public class MetadataDiscoveryResource {
if ( dslQueryFailed ) {
response = searchUsingFullText(query, limit, offset);
}
AtlasPerfTracer.log(perf);
return response;
}
......@@ -125,6 +121,7 @@ public class MetadataDiscoveryResource {
*
* @return JSON representing the type and results.
*/
@Monitored
@GET
@Path("search/dsl")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -132,12 +129,7 @@ public class MetadataDiscoveryResource {
public Response searchUsingQueryDSL(@QueryParam("query") String dslQuery,
@DefaultValue(LIMIT_OFFSET_DEFAULT) @QueryParam("limit") int limit,
@DefaultValue(LIMIT_OFFSET_DEFAULT) @QueryParam("offset") int offset) {
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "MetadataDiscoveryResource.searchUsingQueryDSL(" + dslQuery + ", " + limit + ", " + offset + ")");
}
dslQuery = ParamChecker.notEmpty(dslQuery, "dslQuery cannot be null");
QueryParams queryParams = validateQueryParams(limit, offset);
final String jsonResultStr = discoveryService.searchByDSL(dslQuery, queryParams);
......@@ -151,8 +143,6 @@ public class MetadataDiscoveryResource {
} catch (Throwable e) {
LOG.error("Unable to get entity list for dslQuery {}", dslQuery, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -184,18 +174,14 @@ public class MetadataDiscoveryResource {
* @param gremlinQuery search query in raw gremlin format.
* @return JSON representing the type and results.
*/
@Monitored
@GET
@Path("search/gremlin")
@Consumes(Servlets.JSON_MEDIA_TYPE)
@Produces(Servlets.JSON_MEDIA_TYPE)
@InterfaceAudience.Private
public Response searchUsingGremlinQuery(@QueryParam("query") String gremlinQuery) {
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "MetadataDiscoveryResource.searchUsingGremlinQuery(" + gremlinQuery + ")");
}
gremlinQuery = ParamChecker.notEmpty(gremlinQuery, "gremlinQuery cannot be null or empty");
final List<Map<String, String>> results = discoveryService.searchByGremlin(gremlinQuery);
......@@ -218,8 +204,6 @@ public class MetadataDiscoveryResource {
} catch (Throwable e) {
LOG.error("Unable to get entity list for gremlinQuery {}", gremlinQuery, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -231,6 +215,7 @@ public class MetadataDiscoveryResource {
* @param offset offset to the results returned, used for pagination. offset >= 0. -1 maps to offset 0
* @return JSON representing the type and results.
*/
@Monitored
@GET
@Path("search/fulltext")
@Consumes(Servlets.JSON_MEDIA_TYPE)
......@@ -238,12 +223,7 @@ public class MetadataDiscoveryResource {
public Response searchUsingFullText(@QueryParam("query") String query,
@DefaultValue(LIMIT_OFFSET_DEFAULT) @QueryParam("limit") int limit,
@DefaultValue(LIMIT_OFFSET_DEFAULT) @QueryParam("offset") int offset) {
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "MetadataDiscoveryResource.searchUsingFullText(" + query + ", " + limit + ", " + offset + ")");
}
query = ParamChecker.notEmpty(query, "query cannot be null or empty");
QueryParams queryParams = validateQueryParams(limit, offset);
final String jsonResultStr = discoveryService.searchByFullText(query, queryParams);
......@@ -257,8 +237,6 @@ public class MetadataDiscoveryResource {
} catch (Throwable e) {
LOG.error("Unable to get entity list for query {}", query, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......
......@@ -20,10 +20,9 @@ package org.apache.atlas.web.resources;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.core.ResourceContext;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.AtlasException;
import org.apache.atlas.aspect.Monitored;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.TypeCategory;
import org.apache.atlas.model.typedef.AtlasClassificationDef;
......@@ -89,19 +88,15 @@ public class TypesResource {
* Submits a type definition corresponding to a given type representing a meta model of a
* domain. Could represent things like Hive Database, Hive Table, etc.
*/
@Monitored
@POST
@Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response submit(@Context HttpServletRequest request) {
TypesREST typesRest = resourceContext.getResource(TypesREST.class);
AtlasPerfTracer perf = null;
JSONArray typesResponse = new JSONArray();
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.submit()");
}
final String typeDefinition = Servlets.getRequestPayload(request);
LOG.info("Creating type with definition {} ", typeDefinition);
......@@ -129,8 +124,6 @@ public class TypesResource {
} catch (Throwable e) {
LOG.error("Unable to persist types", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -143,18 +136,14 @@ public class TypesResource {
* @param request
* @return
*/
@Monitored
@PUT
@Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response update(@Context HttpServletRequest request) {
TypesREST typesRest = resourceContext.getResource(TypesREST.class);
AtlasPerfTracer perf = null;
JSONArray typesResponse = new JSONArray();
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.update()");
}
final String typeDefinition = Servlets.getRequestPayload(request);
LOG.info("Updating type with definition {} ", typeDefinition);
......@@ -182,8 +171,6 @@ public class TypesResource {
} catch (Throwable e) {
LOG.error("Unable to persist types", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -192,19 +179,15 @@ public class TypesResource {
*
* @param typeName name of a type which is unique.
*/
@Monitored
@GET
@Path("{typeName}")
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getDefinition(@Context HttpServletRequest request, @PathParam("typeName") String typeName) {
TypesREST typesRest = resourceContext.getResource(TypesREST.class);
JSONObject response = new JSONObject();
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.getDefinition(" + typeName + ")");
}
TypeCategory typeCategory = typeRegistry.getType(typeName).getTypeCategory();
TypesDef typesDef = null;
......@@ -247,8 +230,6 @@ public class TypesResource {
} catch (Throwable e) {
LOG.error("Unable to get type definition for type {}", typeName, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
......@@ -264,6 +245,7 @@ public class TypesResource {
* For example, typeCategory = TRAIT && supertype contains 'X' && supertype !contains 'Y'
* If there is no filter, all the types are returned
*/
@Monitored
@GET
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getTypesByFilter(@Context HttpServletRequest request, @QueryParam("type") String typeCategory,
......@@ -271,12 +253,7 @@ public class TypesResource {
@QueryParam("notsupertype") String notsupertype) throws AtlasBaseException {
TypesREST typesRest = resourceContext.getResource(TypesREST.class);
JSONObject response = new JSONObject();
AtlasPerfTracer perf = null;
try {
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.getTypesByFilter(" + typeCategory + ")");
}
List<String> result = RestUtils.getTypeNames(typesRest.getTypeDefHeaders());
response.put(AtlasClient.RESULTS, new JSONArray(result));
......@@ -291,8 +268,6 @@ public class TypesResource {
} catch (Throwable e) {
LOG.error("Unable to get types list", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} finally {
AtlasPerfTracer.log(perf);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment