You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ol...@apache.org on 2016/04/13 00:55:19 UTC
[2/2] ambari git commit: AMBARI-15807. Initial commit for Logsearch
REST API implementation (rnettleton via oleewere)
AMBARI-15807. Initial commit for Logsearch REST API implementation (rnettleton via oleewere)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/20e66fbb
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/20e66fbb
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/20e66fbb
Branch: refs/heads/trunk
Commit: 20e66fbb2b5c92b755b8d85e8009d64ccb1c5403
Parents: ea0f60b
Author: Bob Nettleton <rn...@hortonworks.com>
Authored: Wed Apr 13 00:30:17 2016 +0200
Committer: oleewere <ol...@gmail.com>
Committed: Wed Apr 13 00:33:47 2016 +0200
----------------------------------------------------------------------
.../resources/LoggingResourceDefinition.java | 44 +++
.../resources/ResourceInstanceFactoryImpl.java | 4 +
.../server/api/services/ClusterService.java | 14 +
.../server/api/services/LoggingService.java | 232 ++++++++++++++
.../AbstractControllerResourceProvider.java | 2 +
.../internal/AbstractProviderModule.java | 14 +-
.../internal/LoggingResourceProvider.java | 145 +++++++++
.../logging/HostComponentLoggingInfo.java | 55 ++++
.../logging/LogFileDefinitionInfo.java | 84 +++++
.../server/controller/logging/LogFileType.java | 33 ++
.../controller/logging/LogLineResult.java | 315 +++++++++++++++++++
.../controller/logging/LogQueryResponse.java | 123 ++++++++
.../logging/LoggingRequestHelper.java | 29 ++
.../logging/LoggingRequestHelperFactory.java | 35 +++
.../LoggingRequestHelperFactoryImpl.java | 82 +++++
.../logging/LoggingRequestHelperImpl.java | 202 ++++++++++++
.../logging/LoggingSearchPropertyProvider.java | 187 +++++++++++
.../ambari/server/controller/spi/Resource.java | 5 +-
.../src/main/resources/key_properties.json | 3 +
.../controller/logging/LogLineResultTest.java | 135 ++++++++
.../logging/LogQueryResponseTest.java | 226 +++++++++++++
.../LoggingRequestHelperFactoryImplTest.java | 133 ++++++++
.../LoggingSearchPropertyProviderTest.java | 170 ++++++++++
23 files changed, 2266 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/api/resources/LoggingResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/LoggingResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/LoggingResourceDefinition.java
new file mode 100644
index 0000000..b2c1a94
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/LoggingResourceDefinition.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.Collections;
+import java.util.Set;
+
+public class LoggingResourceDefinition extends BaseResourceDefinition {
+
+ public LoggingResourceDefinition() {
+ super(Resource.Type.LoggingQuery);
+ }
+
+
+ @Override
+ public String getPluralName() {
+ return "logging";
+ }
+
+ @Override
+ public String getSingularName() {
+ return "logging";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index c711bed..eed2703 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -429,6 +429,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
resourceDefinition = new SimpleResourceDefinition(Resource.Type.ClusterKerberosDescriptor, "kerberos_descriptor", "kerberos_descriptors");
break;
+ case LoggingQuery:
+ resourceDefinition = new LoggingResourceDefinition();
+ break;
+
default:
throw new IllegalArgumentException("Unsupported resource type: " + type);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
index 371411d..072c4a2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
@@ -651,6 +651,20 @@ public class ClusterService extends BaseService {
return new ClusterKerberosDescriptorService(clusterName);
}
+ /**
+ * Gets the Logging Service
+ *
+ * @param request the request
+ * @param clusterName the cluster name
+ *
+ * @return a new instance of the LoggingService
+ */
+ @Path("{clusterName}/logging")
+ public LoggingService getLogging(@Context javax.ws.rs.core.Request request,
+ @PathParam("clusterName") String clusterName) {
+ return new LoggingService(clusterName);
+ }
+
// ----- helper methods ----------------------------------------------------
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java
new file mode 100644
index 0000000..08ec06e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java
@@ -0,0 +1,232 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.AmbariServer;
+import org.apache.ambari.server.controller.internal.ResourceImpl;
+import org.apache.ambari.server.controller.logging.LogQueryResponse;
+import org.apache.ambari.server.controller.logging.LoggingRequestHelper;
+import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactory;
+import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactoryImpl;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.utils.RetryHelper;
+import org.apache.log4j.Logger;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This Service provides access to the LogSearch query services, including:
+ * - Access to all service log files in a given cluster
+ * - Search query capability across the service logs
+ * - Metrics data regarding logging (log level counts, etc)
+ *
+ */
+public class LoggingService extends BaseService {
+
+ private static final Logger LOG = Logger.getLogger(LoggingService.class);
+
+ public static final String LOGSEARCH_SITE_CONFIG_TYPE_NAME = "logsearch-site";
+
+ public static final String LOGSEARCH_SERVICE_NAME = "LOGSEARCH";
+
+ public static final String LOGSEARCH_SERVER_COMPONENT_NAME = "LOGSEARCH_SERVER";
+
+ private final ControllerFactory controllerFactory;
+
+ private final LoggingRequestHelperFactory helperFactory;
+
+
+ private final String clusterName;
+
+ public LoggingService(String clusterName) {
+ this(clusterName, new DefaultControllerFactory(), new LoggingRequestHelperFactoryImpl());
+ }
+
+ public LoggingService(String clusterName, ControllerFactory controllerFactory, LoggingRequestHelperFactory helperFactory) {
+ this.clusterName = clusterName;
+ this.controllerFactory = controllerFactory;
+ this.helperFactory = helperFactory;
+ }
+
+ @GET
+ @Produces("text/plain")
+ public Response getLogSearchResource(String body, @Context HttpHeaders headers, @Context UriInfo uri) {
+ return handleRequest(headers, body, uri, Request.Type.GET, createLoggingResource());
+ }
+
+ @GET
+ @Path("searchEngine")
+ @Produces("text/plain")
+ public Response getSearchEngine(String body, @Context HttpHeaders headers, @Context UriInfo uri) {
+ //TODO, fix this cast after testing,RWN
+ return handleDirectRequest(headers, body, uri, Request.Type.GET, (MediaType)null);
+ }
+
+ @GET
+ @Path("levelCount")
+ @Produces("text/plain")
+ public Response getLevelCountForCluster(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+ throw new IllegalStateException("not implemented yet");
+ }
+
+ @GET
+ @Path("graphing")
+ @Produces("text/plain")
+ public Response getGraphData(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+ throw new IllegalStateException("not implemented yet");
+ }
+
+
+ private ResourceInstance createLoggingResource() {
+ return createResource(Resource.Type.LoggingQuery,
+ Collections.singletonMap(Resource.Type.LoggingQuery, "logging"));
+ }
+
+
+ /**
+ * Handling method for REST services that don't require the QueryParameter and
+ * partial-response syntax support provided by the Ambari REST framework.
+ *
+ * In the case of the LoggingService, the query parameters passed to the search engine must
+ * be preserved, since they are passed to the LogSearch REST API.
+ *
+ * @param headers
+ * @param body
+ * @param uriInfo
+ * @param requestType
+ * @param mediaType
+ * @return
+ */
+ protected Response handleDirectRequest(HttpHeaders headers, String body, UriInfo uriInfo, Request.Type requestType, MediaType mediaType) {
+
+ MultivaluedMap<String, String> queryParameters =
+ uriInfo.getQueryParameters();
+
+ Map<String, String> enumeratedQueryParameters =
+ new HashMap<String, String>();
+
+
+ for (String queryName : queryParameters.keySet()) {
+ List<String> queryValue = queryParameters.get(queryName);
+ for (String value : queryValue) {
+ enumeratedQueryParameters.put(queryName, value);
+ }
+ }
+
+ AmbariManagementController controller =
+ controllerFactory.getController();
+
+ LoggingRequestHelper requestHelper =
+ helperFactory.getHelper(controller, clusterName);
+
+ LogQueryResponse response =
+ requestHelper.sendQueryRequest(enumeratedQueryParameters);
+
+ if (response != null) {
+ ResultSerializer serializer = mediaType == null ? getResultSerializer() : getResultSerializer(mediaType);
+
+ Result result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK));
+
+ Resource loggingResource = new ResourceImpl(Resource.Type.LoggingQuery);
+ // include the top-level query result properties
+ loggingResource.setProperty("startIndex", response.getStartIndex());
+ loggingResource.setProperty("pageSize", response.getPageSize());
+ loggingResource.setProperty("resultSize", response.getResultSize());
+ loggingResource.setProperty("queryTimeMMS", response.getQueryTimeMS());
+ loggingResource.setProperty("totalCount", response.getTotalCount());
+
+ // include the individual responses
+ loggingResource.setProperty("logList", response.getListOfResults());
+
+ result.getResultTree().addChild(loggingResource, "logging");
+
+ Response.ResponseBuilder builder = Response.status(result.getStatus().getStatusCode()).entity(
+ serializer.serialize(result));
+
+
+ if (mediaType != null) {
+ builder.type(mediaType);
+ }
+
+ RetryHelper.clearAffectedClusters();
+ return builder.build();
+ }
+
+
+
+ //TODO, add error handling and logging here, RWN
+ return null;
+ }
+
+
+ /**
+ * Internal interface that defines an access factory for the
+ * AmbariManagementController. This facilitates simpler unit testing.
+ *
+ */
+ interface ControllerFactory {
+ AmbariManagementController getController();
+ }
+
+ /**
+ * Default implementation of the internal ControllerFactory interface,
+ * which uses the AmbariServer static method to obtain the controller.
+ */
+ private static class DefaultControllerFactory implements ControllerFactory {
+ @Override
+ public AmbariManagementController getController() {
+ return AmbariServer.getController();
+ }
+ }
+
+ private static class LogSearchConnectionInfo {
+
+ private final String hostName;
+ private final String portNumber;
+
+ public LogSearchConnectionInfo(String hostName, String portNumber) {
+ this.hostName = hostName;
+ this.portNumber = portNumber;
+ }
+
+ public String getHostName() {
+ return this.hostName;
+ }
+
+ public String getPortNumber() {
+ return this.portNumber;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index f24da8d..3721113 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -223,6 +223,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
return new VersionDefinitionResourceProvider();
case ClusterKerberosDescriptor:
return new ClusterKerberosDescriptorResourceProvider(managementController);
+ case LoggingQuery:
+ return new LoggingResourceProvider(propertyIds, keyPropertyIds, managementController);
default:
throw new IllegalArgumentException("Unknown type " + type);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
index ca491f2..4ce974d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
@@ -30,6 +30,7 @@ import org.apache.ambari.server.controller.ServiceComponentHostRequest;
import org.apache.ambari.server.controller.ServiceComponentHostResponse;
import org.apache.ambari.server.controller.jmx.JMXHostProvider;
import org.apache.ambari.server.controller.jmx.JMXPropertyProvider;
+import org.apache.ambari.server.controller.logging.LoggingSearchPropertyProvider;
import org.apache.ambari.server.controller.metrics.MetricHostProvider;
import org.apache.ambari.server.controller.metrics.MetricsPropertyProvider;
import org.apache.ambari.server.controller.metrics.MetricsReportPropertyProvider;
@@ -800,11 +801,14 @@ public abstract class AbstractProviderModule implements ProviderModule,
gpp));
providers.add(new HttpPropertyProvider(streamProvider,
- managementController.getClusters(),
- PropertyHelper.getPropertyId("HostRoles", "cluster_name"),
- PropertyHelper.getPropertyId("HostRoles", "host_name"),
- PropertyHelper.getPropertyId("HostRoles", "component_name"),
- HTTP_PROPERTY_REQUESTS));
+ managementController.getClusters(),
+ PropertyHelper.getPropertyId("HostRoles", "cluster_name"),
+ PropertyHelper.getPropertyId("HostRoles", "host_name"),
+ PropertyHelper.getPropertyId("HostRoles", "component_name"),
+ HTTP_PROPERTY_REQUESTS));
+
+ //TODO, this may need to be conditional based on the presence/absence of LogSearch
+ providers.add(new LoggingSearchPropertyProvider());
}
break;
case RootServiceComponent:
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java
new file mode 100644
index 0000000..f2e07bd
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java
@@ -0,0 +1,145 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.logging.LogQueryResponse;
+import org.apache.ambari.server.controller.logging.LoggingRequestHelperImpl;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class LoggingResourceProvider extends AbstractControllerResourceProvider {
+
+ private static final String LOGGING_SEARCH_SERVICE_PROPERTY_ID = PropertyHelper.getPropertyId("Logging", "search_service_name");
+ private static final String LOGGING_SEARCH_TERM_PROPERTY_ID = PropertyHelper.getPropertyId("Logging", "searchTerm");
+ private static final String LOGGING_COMPONENT_PROPERTY_ID = PropertyHelper.getPropertyId("Logging", "component");
+
+ private static final Set<String> PROPERTY_IDS;
+
+ private static final Map<Resource.Type, String> KEY_PROPERTY_IDS;
+
+ static {
+ Set<String> localSet = new HashSet<String>();
+ localSet.add(LOGGING_SEARCH_SERVICE_PROPERTY_ID);
+ localSet.add(LOGGING_SEARCH_TERM_PROPERTY_ID);
+ localSet.add(LOGGING_COMPONENT_PROPERTY_ID);
+
+ PROPERTY_IDS = Collections.unmodifiableSet(localSet);
+
+ Map<Resource.Type, String> localMap =
+ new HashMap<Resource.Type, String>();
+
+ localMap.put(Resource.Type.LoggingQuery, LOGGING_SEARCH_SERVICE_PROPERTY_ID);
+ KEY_PROPERTY_IDS = Collections.unmodifiableMap(localMap);
+
+ }
+
+
+ public LoggingResourceProvider(Set<String> propertyIds,
+ Map<Resource.Type, String> keyPropertyIds,
+ AmbariManagementController controller) {
+
+
+
+ super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller);
+ }
+
+ @Override
+ protected Set<String> getPKPropertyIds() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+ // just a simple text resource for now, to describe the logging service
+ Resource resource = new ResourceImpl(Resource.Type.LoggingQuery);
+ setResourceProperty(resource, LOGGING_SEARCH_SERVICE_PROPERTY_ID, "logging", getRequestPropertyIds(request, predicate));
+
+ LoggingRequestHelperImpl requestHelper =
+ new LoggingRequestHelperImpl();
+
+ Map<String, String> queryParameters =
+ new HashMap<String, String>();
+
+ queryParameters.put("level", "ERROR");
+
+ LogQueryResponse response =
+ requestHelper.sendQueryRequest(queryParameters);
+
+ // include the top-level query result properties
+ resource.setProperty("startIndex", response.getStartIndex());
+ resource.setProperty("pageSize", response.getPageSize());
+ resource.setProperty("resultSize", response.getResultSize());
+ resource.setProperty("queryTimeMMS", response.getQueryTimeMS());
+ resource.setProperty("totalCount", response.getTotalCount());
+
+ // include the individual responses
+ resource.setProperty("logList", response.getListOfResults());
+
+ return Collections.singleton(resource);
+ }
+
+ private static List<Map<String, String>> createTestData(Resource resource) {
+ // just create some test data for verifying basic resource code, not an actual result
+ Map<String, String> levelCounts = new HashMap<String, String>();
+ levelCounts.put("INFO", "100");
+ levelCounts.put("WARN", "250");
+ levelCounts.put("DEBUG", "300");
+
+ resource.setProperty("logLevels", levelCounts);
+
+ List<Map <String, String>> listOfResults = new LinkedList<Map<String, String>>();
+ Map<String, String> resultOne = new HashMap<String, String>();
+ resultOne.put("data", "This is a test sentence.");
+ resultOne.put("score", "100");
+ resultOne.put("level", "INFO");
+ resultOne.put("type", "hdfs_namenode");
+ resultOne.put("host", "c6401.ambari.apache.org");
+ resultOne.put("LoggerName", "NameNodeLogger");
+
+ listOfResults.add(resultOne);
+ return listOfResults;
+ }
+
+ @Override
+ public Set<String> checkPropertyIds(Set<String> propertyIds) {
+ Set<String> unSupportedProperties =
+ super.checkPropertyIds(propertyIds);
+
+ unSupportedProperties.remove("searchTerm");
+
+ return unSupportedProperties;
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java
new file mode 100644
index 0000000..516c322
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.logging;
+
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.List;
+
+public class HostComponentLoggingInfo {
+
+ private String componentName;
+
+ private List<LogFileDefinitionInfo> listOfLogFileDefinitions;
+
+
+ public HostComponentLoggingInfo() {
+ }
+
+ @JsonProperty("name")
+ public String getComponentName() {
+ return componentName;
+ }
+
+ @JsonProperty("name")
+ public void setComponentName(String componentName) {
+ this.componentName = componentName;
+ }
+
+ @JsonProperty("logs")
+ public List<LogFileDefinitionInfo> getListOfLogFileDefinitions() {
+ return listOfLogFileDefinitions;
+ }
+
+ @JsonProperty("logs")
+ public void setListOfLogFileDefinitions(List<LogFileDefinitionInfo> listOfLogFileDefinitions) {
+ this.listOfLogFileDefinitions = listOfLogFileDefinitions;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileDefinitionInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileDefinitionInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileDefinitionInfo.java
new file mode 100644
index 0000000..12fa1ab
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileDefinitionInfo.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.logging;
+
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class LogFileDefinitionInfo {
+
+ private String logFileName;
+
+ private LogFileType logFileType;
+
+ private String searchEngineURL;
+
+ private String logFileTailURL;
+
+ // default, no args constructor, required for Jackson usage
+ public LogFileDefinitionInfo() {
+ }
+
+ protected LogFileDefinitionInfo(String logFileName, LogFileType logFileType, String searchEngineURL, String logFileTailURL) {
+ this.logFileName = logFileName;
+ this.logFileType = logFileType;
+ this.searchEngineURL = searchEngineURL;
+ this.logFileTailURL = logFileTailURL;
+ }
+
+ @JsonProperty("name")
+ public String getLogFileName() {
+ return logFileName;
+ }
+
+ @JsonProperty("name")
+ public void setLogFileName(String logFileName) {
+ this.logFileName = logFileName;
+ }
+
+ @JsonProperty("type")
+ public LogFileType getLogFileType() {
+ return logFileType;
+ }
+
+ @JsonProperty("type")
+ public void setLogFileType(LogFileType logFileType) {
+ this.logFileType = logFileType;
+ }
+
+ @JsonProperty("searchEngineURL")
+ public String getSearchEngineURL() {
+ return searchEngineURL;
+ }
+
+ @JsonProperty("searchEngineURL")
+ public void setSearchEngineURL(String searchEngineURL) {
+ this.searchEngineURL = searchEngineURL;
+ }
+
+ @JsonProperty("logFileTailURL")
+ public String getLogFileTailURL() {
+ return logFileTailURL;
+ }
+
+ @JsonProperty("logFileTailURL")
+ public void setLogFileTailURL(String logFileTailURL) {
+ this.logFileTailURL = logFileTailURL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileType.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileType.java
new file mode 100644
index 0000000..3914f8d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogFileType.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.logging;
+
+
+/**
+ * Simple Enumerated type to describe the type of log file, as defined by LogSearch.
+ *
+ */
+public enum LogFileType {
+
+ // service logs include most log files in Hadoop
+ SERVICE,
+ // audit logs include security access information, not normally enabled by default
+ AUDIT
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java
new file mode 100644
index 0000000..b6ab6bd
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java
@@ -0,0 +1,315 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.logging;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class represents a single entry from a LogSearch query.
+ *
+ */
+public class LogLineResult {
+
+ private final Map<String, String> mapOfLogLineProperties =
+ new HashMap<String, String>();
+
+ private String clusterName;
+
+ private String logMethod;
+
+ private String logLevel;
+
+ private String eventCount;
+
+ private String ipAddress;
+
+ private String componentType;
+
+ private String sequenceNumber;
+
+ private String logFilePath;
+
+ private String sourceFile;
+
+ private String sourceFileLineNumber;
+
+ private String hostName;
+
+ private String logMessage;
+
+ private String loggerName;
+
+ private String id;
+
+ private String messageMD5;
+
+ private String logTime;
+
+ private String eventMD5;
+
+ private String logFileLineNumber;
+
+ private String ttl;
+
+ private String expirationTime;
+
+ private String version;
+
+ private String thread_name;
+
+ public LogLineResult() {
+
+ }
+
+ public LogLineResult(Map<String, String> propertiesMap) {
+ mapOfLogLineProperties.putAll(propertiesMap);
+ }
+
+ public String getProperty(String propertyName) {
+ return mapOfLogLineProperties.get(propertyName);
+ }
+
+ public boolean doesPropertyExist(String propertyName) {
+ return mapOfLogLineProperties.containsKey(propertyName);
+ }
+
+
+ @JsonProperty("cluster")
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ @JsonProperty("cluster")
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ @JsonProperty("method")
+ public String getLogMethod() {
+ return logMethod;
+ }
+
+ @JsonProperty("method")
+ public void setLogMethod(String logMethod) {
+ this.logMethod = logMethod;
+ }
+
+ @JsonProperty("level")
+ public String getLogLevel() {
+ return logLevel;
+ }
+
+ @JsonProperty("level")
+ public void setLogLevel(String logLevel) {
+ this.logLevel = logLevel;
+ }
+
+ @JsonProperty("event_count")
+ public String getEventCount() {
+ return eventCount;
+ }
+
+ @JsonProperty("event_count")
+ public void setEventCount(String eventCount) {
+ this.eventCount = eventCount;
+ }
+
+ @JsonProperty("ip")
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ @JsonProperty("ip")
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ @JsonProperty("type")
+ public String getComponentType() {
+ return componentType;
+ }
+
+ @JsonProperty("type")
+ public void setComponentType(String componentType) {
+ this.componentType = componentType;
+ }
+
+ @JsonProperty("seq_num")
+ public String getSequenceNumber() {
+ return sequenceNumber;
+ }
+
+ @JsonProperty("seq_num")
+ public void setSequenceNumber(String sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ @JsonProperty("path")
+ public String getLogFilePath() {
+ return logFilePath;
+ }
+
+ @JsonProperty("path")
+ public void setLogFilePath(String logFilePath) {
+ this.logFilePath = logFilePath;
+ }
+
+ @JsonProperty("file")
+ public String getSourceFile() {
+ return sourceFile;
+ }
+
+ @JsonProperty("file")
+ public void setSourceFile(String sourceFile) {
+ this.sourceFile = sourceFile;
+ }
+
+ @JsonProperty("line_number")
+ public String getSourceFileLineNumber() {
+ return sourceFileLineNumber;
+ }
+
+ @JsonProperty("line_number")
+ public void setSourceFileLineNumber(String sourceFileLineNumber) {
+ this.sourceFileLineNumber = sourceFileLineNumber;
+ }
+
+ @JsonProperty("host")
+ public String getHostName() {
+ return hostName;
+ }
+
+ @JsonProperty("host")
+ public void setHostName(String hostName) {
+ this.hostName = hostName;
+ }
+
+ @JsonProperty("log_message")
+ public String getLogMessage() {
+ return logMessage;
+ }
+
+ @JsonProperty("log_message")
+ public void setLogMessage(String logMessage) {
+ this.logMessage = logMessage;
+ }
+
+ @JsonProperty("logger_name")
+ public String getLoggerName() {
+ return loggerName;
+ }
+
+ @JsonProperty("logger_name")
+ public void setLoggerName(String loggerName) {
+ this.loggerName = loggerName;
+ }
+
+ @JsonProperty("id")
+ public String getId() {
+ return id;
+ }
+
+ @JsonProperty("id")
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @JsonProperty("message_md5")
+ public String getMessageMD5() {
+ return messageMD5;
+ }
+
+ @JsonProperty("message_md5")
+ public void setMessageMD5(String messageMD5) {
+ this.messageMD5 = messageMD5;
+ }
+
+ @JsonProperty("logtime")
+ public String getLogTime() {
+ return logTime;
+ }
+
+ @JsonProperty("logtime")
+ public void setLogTime(String logTime) {
+ this.logTime = logTime;
+ }
+
+ @JsonProperty("event_md5")
+ public String getEventMD5() {
+ return eventMD5;
+ }
+
+ @JsonProperty("event_md5")
+ public void setEventMD5(String eventMD5) {
+ this.eventMD5 = eventMD5;
+ }
+
+ @JsonProperty("logfile_line_number")
+ public String getLogFileLineNumber() {
+ return logFileLineNumber;
+ }
+
+ @JsonProperty("logfile_line_number")
+ public void setLogFileLineNumber(String logFileLineNumber) {
+ this.logFileLineNumber = logFileLineNumber;
+ }
+
+ @JsonProperty("_ttl_")
+ public String getTtl() {
+ return ttl;
+ }
+
+ @JsonProperty("_ttl_")
+ public void setTtl(String ttl) {
+ this.ttl = ttl;
+ }
+
+ @JsonProperty("_expire_at_")
+ public String getExpirationTime() {
+ return expirationTime;
+ }
+
+ @JsonProperty("_expire_at_")
+ public void setExpirationTime(String expirationTime) {
+ this.expirationTime = expirationTime;
+ }
+
+ @JsonProperty("_version_")
+ public String getVersion() {
+ return version;
+ }
+
+ @JsonProperty("_version_")
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ @JsonProperty("thread_name")
+ public String getThreadName() {
+ return thread_name;
+ }
+
+ @JsonProperty("thread_name")
+ public void setThreadName(String thread_name) {
+ this.thread_name = thread_name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogQueryResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogQueryResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogQueryResponse.java
new file mode 100644
index 0000000..9bde7a5
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogQueryResponse.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.logging;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.util.JSONPObject;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class respresents the results of a LogSearch query, as returned by
+ * a call to the LogSearch service.
+ *
+ */
+public class LogQueryResponse {
+
+
+ private String startIndex;
+
+ private String pageSize;
+
+ private String totalCount;
+
+ private String resultSize;
+
+ private String queryTimeMS;
+
+
+ private List<LogLineResult> listOfResults;
+
+ private StringBuffer resultString;
+
+ public LogQueryResponse() {
+
+ }
+
+ public LogQueryResponse(StringBuffer resultString) {
+ this.resultString = resultString;
+ }
+
+ @JsonProperty("logList")
+ public List<LogLineResult> getListOfResults() {
+ return listOfResults;
+ }
+
+ @JsonProperty("logList")
+ public void setLogList(List<LogLineResult> logList) {
+ this.listOfResults = logList;
+ }
+
+ @JsonProperty("startIndex")
+ public String getStartIndex() {
+ return startIndex;
+ }
+
+ @JsonProperty("startIndex")
+ public void setStartIndex(String startIndex) {
+ this.startIndex = startIndex;
+ }
+
+ @JsonProperty("pageSize")
+ public String getPageSize() {
+ return pageSize;
+ }
+
+ @JsonProperty("pageSize")
+ public void setPageSize(String pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ @JsonProperty("totalCount")
+ public String getTotalCount() {
+ return totalCount;
+ }
+
+ @JsonProperty("totalCount")
+ public void setTotalCount(String totalCount) {
+ this.totalCount = totalCount;
+ }
+
+ @JsonProperty("resultSize")
+ public String getResultSize() {
+ return resultSize;
+ }
+
+ @JsonProperty("resultSize")
+ public void setResultSize(String resultSize) {
+ this.resultSize = resultSize;
+ }
+
+ @JsonProperty("queryTimeMS")
+ public String getQueryTimeMS() {
+ return queryTimeMS;
+ }
+
+ @JsonProperty("queryTimeMS")
+ public void setQueryTimeMS(String queryTimeMS) {
+ this.queryTimeMS = queryTimeMS;
+ }
+
+ public StringBuffer getResultString() {
+ return resultString;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java
new file mode 100644
index 0000000..c1fe1d2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java
@@ -0,0 +1,29 @@
+package org.apache.ambari.server.controller.logging;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 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.
+ */
+public interface LoggingRequestHelper {
+
+ public LogQueryResponse sendQueryRequest(Map<String, String> queryParameters);
+
+ public Set<String> sendGetLogFileNamesRequest(String componentName, String hostName);
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactory.java
new file mode 100644
index 0000000..5ccab6f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactory.java
@@ -0,0 +1,35 @@
+package org.apache.ambari.server.controller.logging;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+
+/**
+ * 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.
+ */
+public interface LoggingRequestHelperFactory {
+
+ /**
+ * Obtain a new instance of a LoggingRequestHelper, which can
+ * be used to connect to the given cluster
+ * @param ambariManagementController
+ * @param clusterName name of cluster that includes a LogSearch deployment
+ *
+ * @return an instance of LoggingRequestHelper that can be used to
+ * connect to this cluster's LogSearch service
+ */
+ LoggingRequestHelper getHelper(AmbariManagementController ambariManagementController, String clusterName);
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java
new file mode 100644
index 0000000..69d4f3c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.logging;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.log4j.Logger;
+
+import java.util.List;
+
+public class LoggingRequestHelperFactoryImpl implements LoggingRequestHelperFactory {
+
+ private static final Logger LOG = Logger.getLogger(LoggingRequestHelperFactoryImpl.class);
+
+ private static final String LOGSEARCH_SITE_CONFIG_TYPE_NAME = "logsearch-site";
+
+ private static final String LOGSEARCH_SERVICE_NAME = "LOGSEARCH";
+
+ private static final String LOGSEARCH_SERVER_COMPONENT_NAME = "LOGSEARCH_SERVER";
+
+ private static final String LOGSEARCH_UI_PORT_PROPERTY_NAME = "logsearch.ui.port";
+
+
+ @Override
+ public LoggingRequestHelper getHelper(AmbariManagementController ambariManagementController, String clusterName) {
+ Clusters clusters =
+ ambariManagementController.getClusters();
+
+ try {
+ Cluster cluster = clusters.getCluster(clusterName);
+ if (cluster != null) {
+ Config logSearchSiteConfig =
+ cluster.getDesiredConfigByType(LOGSEARCH_SITE_CONFIG_TYPE_NAME);
+
+ List<ServiceComponentHost> listOfMatchingHosts =
+ cluster.getServiceComponentHosts(LOGSEARCH_SERVICE_NAME, LOGSEARCH_SERVER_COMPONENT_NAME);
+
+ if (listOfMatchingHosts.size() == 0) {
+ LOG.info("No matching LOGSEARCH_SERVER instances found, this may indicate a deployment problem. Please verify that LogSearch is deployed and running.");
+ return null;
+ }
+
+ if (listOfMatchingHosts.size() > 1) {
+ LOG.warn("More than one LOGSEARCH_SERVER instance found, this may be a deployment error. Only the first LOGSEARCH_SERVER instance will be used.");
+ }
+
+ ServiceComponentHost serviceComponentHost =
+ listOfMatchingHosts.get(0);
+
+ final String logSearchHostName = serviceComponentHost.getHostName();
+ final String logSearchPortNumber =
+ logSearchSiteConfig.getProperties().get(LOGSEARCH_UI_PORT_PROPERTY_NAME);
+
+ return new LoggingRequestHelperImpl(logSearchHostName, logSearchPortNumber);
+ }
+ } catch (AmbariException ambariException) {
+ LOG.error("Error occurred while trying to obtain the cluster, cluster name = " + clusterName, ambariException);
+ }
+
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java
new file mode 100644
index 0000000..2c3d941
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java
@@ -0,0 +1,202 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.logging;
+
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.log4j.Logger;
+import org.codehaus.jackson.map.AnnotationIntrospector;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectReader;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Convenience class to handle the connection details of a LogSearch query request.
+ *
+ */
+public class LoggingRequestHelperImpl implements LoggingRequestHelper {
+
+ private Logger LOG = Logger.getLogger(LoggingRequestHelperImpl.class);
+
+ //TODO, hardcoded localhost for LogSearch service for dev purposes, will switch to config after POC finished
+
+
+ private static String DEFAULT_HOSTNAME = "localhost";
+
+ private static String DEFAULT_PORT = "61888";
+
+ private static String LOGSEARCH_QUERY_PATH = "/service/dashboard/solr/logs_search";
+
+ private static String DEFAULT_LOGSEARCH_USER = "admin";
+
+ private static String DEFAULT_LOGSEARCH_PWD = "admin";
+
+ private final String hostName;
+
+ private final String portNumber;
+
+
+ public LoggingRequestHelperImpl() {
+ this(DEFAULT_HOSTNAME, DEFAULT_PORT);
+ }
+
+ public LoggingRequestHelperImpl(String hostName, String portNumber) {
+ this.hostName = hostName;
+ this.portNumber = portNumber;
+ }
+
+ public LogQueryResponse sendQueryRequest(Map<String, String> queryParameters) {
+ try {
+ // use the Apache builder to create the correct URI
+ URI logSearchURI = createLogSearchQueryURI(queryParameters);
+ LOG.info("Attempting to connect to LogSearch server at " + logSearchURI);
+
+ HttpURLConnection httpURLConnection = (HttpURLConnection)logSearchURI.toURL().openConnection();
+ httpURLConnection.setRequestMethod("GET");
+ setupBasicAuthentication(httpURLConnection);
+ StringBuffer buffer = readQueryResponseFromServer(httpURLConnection);
+
+ // setup a reader for the JSON response
+ StringReader stringReader =
+ new StringReader(buffer.toString());
+
+ // setup the Jackson mapper/reader to read in the data structure
+ ObjectMapper mapper = createJSONObjectMapper();
+
+ ObjectReader logQueryResponseReader =
+ mapper.reader(LogQueryResponse.class);
+
+ LogQueryResponse queryResult =
+ logQueryResponseReader.readValue(stringReader);
+
+ LOG.debug("DEBUG: response from LogSearch was: " + buffer);
+
+ return queryResult;
+
+ } catch (MalformedURLException e) {
+ // TODO, need better error handling here
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ } catch (IOException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ } catch (URISyntaxException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+
+ return null;
+ }
+
+ public Set<String> sendGetLogFileNamesRequest(String componentName, String hostName) {
+ Map<String, String> queryParameters =
+ new HashMap<String, String>();
+
+ // TODO, this current method will be a temporary workaround
+ // TODO, until the new LogSearch API method is available to handle this request
+
+ queryParameters.put("host", hostName);
+ queryParameters.put("components_name",componentName);
+ // ask for page size of 1, since we really only want a single entry to
+ // get the file path name
+ queryParameters.put("pageSize", "1");
+
+ LogQueryResponse response = sendQueryRequest(queryParameters);
+ if ((response != null) && (!response.getListOfResults().isEmpty())) {
+ LogLineResult lineOne = response.getListOfResults().get(0);
+ // this assumes that each component has only one associated log file,
+ // which may not always hold true
+ LOG.info("For componentName = " + componentName + ", log file name is = " + lineOne.getLogFilePath());
+ return Collections.singleton(lineOne.getLogFilePath());
+
+ }
+
+ return Collections.emptySet();
+ }
+
+ private URI createLogSearchQueryURI(Map<String, String> queryParameters) throws URISyntaxException {
+ URIBuilder uriBuilder = new URIBuilder();
+ uriBuilder.setScheme("http");
+ uriBuilder.setHost(hostName);
+ uriBuilder.setPort(Integer.valueOf(portNumber));
+ uriBuilder.setPath(LOGSEARCH_QUERY_PATH);
+
+ // add any query strings specified
+ for (String key : queryParameters.keySet()) {
+ uriBuilder.addParameter(key, queryParameters.get(key));
+ }
+
+ return uriBuilder.build();
+ }
+
+ protected ObjectMapper createJSONObjectMapper() {
+ ObjectMapper mapper =
+ new ObjectMapper();
+ AnnotationIntrospector introspector =
+ new JacksonAnnotationIntrospector();
+ mapper.setAnnotationIntrospector(introspector);
+ mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
+ return mapper;
+ }
+
+ private StringBuffer readQueryResponseFromServer(HttpURLConnection httpURLConnection) throws IOException {
+ InputStream resultStream = null;
+ try {
+ // read in the response from LogSearch
+ resultStream = httpURLConnection.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(resultStream));
+ LOG.info("Response code from LogSearch Service is = " + httpURLConnection.getResponseCode());
+
+ String line = reader.readLine();
+ StringBuffer buffer = new StringBuffer();
+ while (line != null) {
+ buffer.append(line);
+ line = reader.readLine();
+ }
+ return buffer;
+ } finally {
+ // make sure to close the stream after request is completed
+ if (resultStream != null) {
+ resultStream.close();
+ }
+ }
+ }
+
+ private static void setupBasicAuthentication(HttpURLConnection httpURLConnection) {
+ //TODO, using hard-coded Base64 auth for now, need to revisit this
+ String encodedCredentials =
+ Base64.encodeBase64String((DEFAULT_LOGSEARCH_USER + ":" + DEFAULT_LOGSEARCH_PWD).getBytes());
+ httpURLConnection.setRequestProperty("Authorization", "Basic " + encodedCredentials);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java
new file mode 100644
index 0000000..6b4a8a4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java
@@ -0,0 +1,187 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.logging;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.AmbariServer;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.PropertyProvider;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.state.ComponentInfo;
+import org.apache.ambari.server.state.LogDefinition;
+import org.apache.ambari.server.state.StackId;
+import org.apache.log4j.Logger;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+public class LoggingSearchPropertyProvider implements PropertyProvider {
+
+ private static final Logger LOG = Logger.getLogger(LoggingSearchPropertyProvider.class);
+
+ private static final String CLUSTERS_PATH = "/api/v1/clusters";
+
+ private static final String PATH_TO_SEARCH_ENGINE = "/logging/searchEngine";
+
+ private static final String DEFAULT_PAGE_SIZE = "50";
+
+ private static final String COMPONENT_QUERY_PARAMETER_NAME = "components_name";
+
+ private static final String HOST_QUERY_PARAMETER_NAME = "host";
+
+ private static final String PAGE_SIZE_QUERY_PARAMETER_NAME = "pageSize";
+
+ private final LoggingRequestHelperFactory requestHelperFactory;
+
+ private final ControllerFactory controllerFactory;
+
+ public LoggingSearchPropertyProvider() {
+ this(new LoggingRequestHelperFactoryImpl(), new DefaultControllerFactory());
+ }
+
+ protected LoggingSearchPropertyProvider(LoggingRequestHelperFactory requestHelperFactory, ControllerFactory controllerFactory) {
+ this.requestHelperFactory = requestHelperFactory;
+ this.controllerFactory = controllerFactory;
+ }
+
+
+
+ @Override
+ public Set<Resource> populateResources(Set<Resource> resources, Request request, Predicate predicate) throws SystemException {
+
+ AmbariManagementController controller =
+ controllerFactory.getAmbariManagementController();
+
+ for (Resource resource : resources) {
+ // obtain the required identifying properties on the host component resource
+ final String componentName = (String)resource.getPropertyValue(PropertyHelper.getPropertyId("HostRoles", "component_name"));
+ final String hostName = (String) resource.getPropertyValue(PropertyHelper.getPropertyId("HostRoles", "host_name"));
+ final String clusterName = (String) resource.getPropertyValue(PropertyHelper.getPropertyId("HostRoles", "cluster_name"));
+
+ // query the stack definitions to find the correct component name (stack name mapped to LogSearch-defined name)
+ final String mappedComponentNameForLogSearch =
+ getMappedComponentNameForSearch(clusterName, componentName, controller);
+
+ if (mappedComponentNameForLogSearch != null) {
+ HostComponentLoggingInfo loggingInfo =
+ new HostComponentLoggingInfo();
+
+ // make query to LogSearch server to find the associated file names
+ // create helper instance using factory
+ LoggingRequestHelper requestHelper =
+ requestHelperFactory.getHelper(controller, clusterName);
+
+ // send query to obtain logging metadata
+ Set<String> logFileNames =
+ requestHelper.sendGetLogFileNamesRequest(mappedComponentNameForLogSearch, hostName);
+
+ if ((logFileNames != null) && (!logFileNames.isEmpty())) {
+ loggingInfo.setComponentName(mappedComponentNameForLogSearch);
+ List<LogFileDefinitionInfo> listOfFileDefinitions =
+ new LinkedList<LogFileDefinitionInfo>();
+
+ for (String fileName : logFileNames) {
+ // generate the URIs that can be used by clients to obtain search results/tail log results/etc
+ final String searchEngineURI = controller.getAmbariServerURI(getFullPathToSearchEngine(clusterName));
+ final String logFileTailURI = createLogFileTailURI(searchEngineURI, mappedComponentNameForLogSearch, hostName);
+ // all log files are assumed to be service types for now
+ listOfFileDefinitions.add(new LogFileDefinitionInfo(fileName, LogFileType.SERVICE, searchEngineURI, logFileTailURI));
+ }
+
+ loggingInfo.setListOfLogFileDefinitions(listOfFileDefinitions);
+
+ LOG.info("Adding logging info for component name = " + componentName + " on host name = " + hostName);
+ // add the logging metadata for this host component
+ resource.setProperty("logging", loggingInfo);
+ } else {
+ LOG.error("Error occurred while making request to LogSearch service, unable to populate logging properties on this resource");
+ }
+ }
+
+ }
+
+ return resources;
+ }
+
+ private String getMappedComponentNameForSearch(String clusterName, String componentName, AmbariManagementController controller) {
+ try {
+ AmbariMetaInfo metaInfo = controller.getAmbariMetaInfo();
+ StackId stackId =
+ controller.getClusters().getCluster(clusterName).getCurrentStackVersion();
+ final String stackName = stackId.getStackName();
+ final String stackVersion = stackId.getStackVersion();
+ final String serviceName =
+ metaInfo.getComponentToService(stackName, stackVersion, componentName);
+
+ ComponentInfo componentInfo =
+ metaInfo.getComponent(stackName, stackVersion, serviceName, componentName);
+ if (componentInfo != null) {
+ List<LogDefinition> listOfLogs =
+ componentInfo.getLogs();
+ // for now, the assumption is that there is only one log file associated with each
+ // component in LogSearch, but this may change in the future
+ if ((listOfLogs != null) && (!listOfLogs.isEmpty())) {
+ LogDefinition definition = listOfLogs.get(0);
+ // return the first log id we find
+ return definition.getLogId();
+ }
+ }
+
+ } catch (AmbariException e) {
+ LOG.error("Error occurred while attempting to locate the log component name for component = " + componentName, e);
+ }
+
+ return null;
+ }
+
+ private String getFullPathToSearchEngine(String clusterName) {
+ return CLUSTERS_PATH + "/" + clusterName + PATH_TO_SEARCH_ENGINE;
+ }
+
+ protected static String createLogFileTailURI(String searchEngineURI, String componentName, String hostName) {
+ return searchEngineURI + "?" + COMPONENT_QUERY_PARAMETER_NAME + "=" + componentName + "&" + HOST_QUERY_PARAMETER_NAME + "=" + hostName
+ + "&" + PAGE_SIZE_QUERY_PARAMETER_NAME + "=" + DEFAULT_PAGE_SIZE;
+ }
+
+ @Override
+ public Set<String> checkPropertyIds(Set<String> propertyIds) {
+ return Collections.emptySet();
+ }
+
+ /**
+ * Internal interface used to control how the AmbariManagementController
+ * instance is obtained. This is useful for unit testing as well.
+ */
+ interface ControllerFactory {
+ AmbariManagementController getAmbariManagementController();
+ }
+
+ private static class DefaultControllerFactory implements ControllerFactory {
+ @Override
+ public AmbariManagementController getAmbariManagementController() {
+ return AmbariServer.getController();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 63af4c4..5a8476d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -154,7 +154,8 @@ public interface Resource {
RoleAuthorization,
UserAuthorization,
VersionDefinition,
- ClusterKerberosDescriptor;
+ ClusterKerberosDescriptor,
+ LoggingQuery;
/**
* Get the {@link Type} that corresponds to this InternalType.
@@ -270,6 +271,8 @@ public interface Resource {
public static final Type UserAuthorization = InternalType.UserAuthorization.getType();
public static final Type VersionDefinition = InternalType.VersionDefinition.getType();
public static final Type ClusterKerberosDescriptor = InternalType.ClusterKerberosDescriptor.getType();
+ public static final Type LoggingQuery = InternalType.LoggingQuery.getType();
+
/**
* The type name.
*/
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 46a6cf9..8069349 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -150,5 +150,8 @@
},
"KerberosDescriptor": {
"KerberosDescriptor": "KerberosDescriptors/kerberos_descriptor_name"
+ },
+ "LoggingQuery": {
+ "Cluster" : "logging/cluster_name"
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLineResultTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLineResultTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLineResultTest.java
new file mode 100644
index 0000000..069f448
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLineResultTest.java
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.ambari.server.controller.logging;
+
+
+import org.codehaus.jackson.map.AnnotationIntrospector;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectReader;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
+import org.junit.Test;
+
+import java.io.StringReader;
+
+import static org.junit.Assert.*;
+
+public class LogLineResultTest {
+
+ private static final String TEST_JSON_DATA_SINGLE_ENTRY =
+ "{" +
+
+ " \"cluster\" : \"clusterone\"," +
+ " \"method\" : \"chooseUnderReplicatedBlocks\"," +
+ " \"level\" : \"INFO\"," +
+ " \"event_count\" : 1," +
+ " \"ip\" : \"192.168.1.1\"," +
+ " \"type\" : \"hdfs_namenode\"," +
+ " \"thread_name\" : \"thread-id-one\"," +
+ " \"seq_num\" : 10584," +
+ " \"path\" : \"/var/log/hadoop/hdfs/hadoop-hdfs-namenode-c6401.ambari.apache.org.log\"," +
+ " \"file\" : \"UnderReplicatedBlocks.java\"," +
+ " \"line_number\" : 394," +
+ " \"host\" : \"c6401.ambari.apache.org\"," +
+ " \"log_message\" : \"chooseUnderReplicatedBlocks selected 2 blocks at priority level 0; Total=2 Reset bookmarks? false\"," +
+ " \"logger_name\" : \"BlockStateChange\"," +
+ " \"id\" : \"9c5562fb-123f-47c8-aaf5-b5e407326c08\"," +
+ " \"message_md5\" : \"-3892769501348410581\"," +
+ " \"logtime\" : 1458148749036," +
+ " \"event_md5\" : \"1458148749036-2417481968206345035\"," +
+ " \"logfile_line_number\" : 2084," +
+ " \"_ttl_\" : \"+7DAYS\"," +
+ " \"_expire_at_\" : 1458753550322," +
+ " \"_version_\" : 1528979784023932928" +
+ " }";
+
+
+
+ @Test
+ public void testBasicParsing() throws Exception {
+ // setup a reader for the test JSON data
+ StringReader stringReader =
+ new StringReader(TEST_JSON_DATA_SINGLE_ENTRY);
+
+ // setup the Jackson mapper/reader to read in the data structure
+ ObjectMapper mapper =
+ new ObjectMapper();
+ AnnotationIntrospector introspector =
+ new JacksonAnnotationIntrospector();
+ mapper.setAnnotationIntrospector(introspector);
+ mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
+
+
+ ObjectReader logLineResultReader =
+ mapper.reader(LogLineResult.class);
+
+ LogLineResult result =
+ logLineResultReader.readValue(stringReader);
+
+ // verify that all fields in this class are parsed as expected
+ assertEquals("Cluster name not parsed properly",
+ "clusterone", result.getClusterName());
+ assertEquals("Method Name not parsed properly",
+ "chooseUnderReplicatedBlocks", result.getLogMethod());
+ assertEquals("Log Level not parsed properly",
+ "INFO", result.getLogLevel());
+ assertEquals("event_count not parsed properly",
+ "1", result.getEventCount());
+ assertEquals("ip address not parsed properly",
+ "192.168.1.1", result.getIpAddress());
+ assertEquals("component type not parsed properly",
+ "hdfs_namenode", result.getComponentType());
+ assertEquals("sequence number not parsed properly",
+ "10584", result.getSequenceNumber());
+ assertEquals("log file path not parsed properly",
+ "/var/log/hadoop/hdfs/hadoop-hdfs-namenode-c6401.ambari.apache.org.log", result.getLogFilePath());
+ assertEquals("log src file name not parsed properly",
+ "UnderReplicatedBlocks.java", result.getSourceFile());
+ assertEquals("log src line number not parsed properly",
+ "394", result.getSourceFileLineNumber());
+ assertEquals("host name not parsed properly",
+ "c6401.ambari.apache.org", result.getHostName());
+ assertEquals("log message not parsed properly",
+ "chooseUnderReplicatedBlocks selected 2 blocks at priority level 0; Total=2 Reset bookmarks? false", result.getLogMessage());
+ assertEquals("logger name not parsed properly",
+ "BlockStateChange", result.getLoggerName());
+ assertEquals("id not parsed properly",
+ "9c5562fb-123f-47c8-aaf5-b5e407326c08", result.getId());
+ assertEquals("message MD5 not parsed properly",
+ "-3892769501348410581", result.getMessageMD5());
+ assertEquals("log time not parsed properly",
+ "1458148749036", result.getLogTime());
+ assertEquals("event MD5 not parsed properly",
+ "1458148749036-2417481968206345035", result.getEventMD5());
+ assertEquals("logfile line number not parsed properly",
+ "2084", result.getLogFileLineNumber());
+ assertEquals("ttl not parsed properly",
+ "+7DAYS", result.getTtl());
+ assertEquals("expire at not parsed properly",
+ "1458753550322", result.getExpirationTime());
+ assertEquals("version not parsed properly",
+ "1528979784023932928", result.getVersion());
+ assertEquals("thread_name not parsed properly",
+ "thread-id-one", result.getThreadName());
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/20e66fbb/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogQueryResponseTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogQueryResponseTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogQueryResponseTest.java
new file mode 100644
index 0000000..d281d6e
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogQueryResponseTest.java
@@ -0,0 +1,226 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.logging;
+
+
+import org.codehaus.jackson.map.AnnotationIntrospector;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectReader;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
+import org.junit.Test;
+
+import java.io.StringReader;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class LogQueryResponseTest {
+
+ private static final String TEST_JSON_INPUT_TWO_LIST_ENTRIES =
+ "{" +
+ " \"startIndex\" : 0," +
+ " \"pageSize\" : 5," +
+ " \"totalCount\" : 10452," +
+ " \"resultSize\" : 5," +
+ " \"queryTimeMS\" : 1458148754113," +
+ " \"logList\" : [ {" +
+ " \"cluster\" : \"clusterone\"," +
+ " \"method\" : \"chooseUnderReplicatedBlocks\"," +
+ " \"level\" : \"INFO\"," +
+ " \"event_count\" : 1," +
+ " \"ip\" : \"192.168.1.1\"," +
+ " \"type\" : \"hdfs_namenode\"," +
+ " \"seq_num\" : 10584," +
+ " \"path\" : \"/var/log/hadoop/hdfs/hadoop-hdfs-namenode-c6401.ambari.apache.org.log\"," +
+ " \"file\" : \"UnderReplicatedBlocks.java\"," +
+ " \"line_number\" : 394," +
+ " \"host\" : \"c6401.ambari.apache.org\"," +
+ " \"log_message\" : \"chooseUnderReplicatedBlocks selected 2 blocks at priority level 0; Total=2 Reset bookmarks? false\"," +
+ " \"logger_name\" : \"BlockStateChange\"," +
+ " \"id\" : \"9c5562fb-123f-47c8-aaf5-b5e407326c08\"," +
+ " \"message_md5\" : \"-3892769501348410581\"," +
+ " \"logtime\" : 1458148749036," +
+ " \"event_md5\" : \"1458148749036-2417481968206345035\"," +
+ " \"logfile_line_number\" : 2084," +
+ " \"_ttl_\" : \"+7DAYS\"," +
+ " \"_expire_at_\" : 1458753550322," +
+ " \"_version_\" : 1528979784023932928" +
+ " }, {" +
+ " \"cluster\" : \"clusterone\"," +
+ " \"method\" : \"putMetrics\"," +
+ " \"level\" : \"WARN\"," +
+ " \"event_count\" : 1," +
+ " \"ip\" : \"192.168.1.1\"," +
+ " \"type\" : \"yarn_resourcemanager\"," +
+ " \"seq_num\" : 10583," +
+ " \"path\" : \"/var/log/hadoop-yarn/yarn/yarn-yarn-resourcemanager-c6401.ambari.apache.org.log\"," +
+ " \"file\" : \"HadoopTimelineMetricsSink.java\"," +
+ " \"line_number\" : 262," +
+ " \"host\" : \"c6401.ambari.apache.org\"," +
+ " \"log_message\" : \"Unable to send metrics to collector by address:http://c6401.ambari.apache.org:6188/ws/v1/timeline/metrics\"," +
+ " \"logger_name\" : \"timeline.HadoopTimelineMetricsSink\"," +
+ " \"id\" : \"8361c5a9-5b1c-4f44-bc8f-4c6f07d94228\"," +
+ " \"message_md5\" : \"5942185045779825717\"," +
+ " \"logtime\" : 1458148746937," +
+ " \"event_md5\" : \"14581487469371427138486123628676\"," +
+ " \"logfile_line_number\" : 549," +
+ " \"_ttl_\" : \"+7DAYS\"," +
+ " \"_expire_at_\" : 1458753550322," +
+ " \"_version_\" : 1528979784022884357" +
+ " }" +
+ "]" +
+ "}";
+
+
+ @Test
+ public void testBasicParsing() throws Exception {
+ // setup a reader for the test JSON data
+ StringReader stringReader =
+ new StringReader(TEST_JSON_INPUT_TWO_LIST_ENTRIES);
+
+ // setup the Jackson mapper/reader to read in the data structure
+ ObjectMapper mapper =
+ new ObjectMapper();
+ AnnotationIntrospector introspector =
+ new JacksonAnnotationIntrospector();
+ mapper.setAnnotationIntrospector(introspector);
+ mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
+
+
+ ObjectReader logQueryResponseReader =
+ mapper.reader(LogQueryResponse.class);
+
+ LogQueryResponse result =
+ logQueryResponseReader.readValue(stringReader);
+
+ assertEquals("startIndex not parsed properly",
+ "0", result.getStartIndex());
+ assertEquals("pageSize not parsed properly",
+ "5", result.getPageSize());
+ assertEquals("totalCount not parsed properly",
+ "10452", result.getTotalCount());
+ assertEquals("resultSize not parsed properly",
+ "5", result.getResultSize());
+ assertEquals("queryTimeMS not parsed properly",
+ "1458148754113", result.getQueryTimeMS());
+
+ assertEquals("incorrect number of LogLineResult items parsed",
+ 2, result.getListOfResults().size());
+
+ List<LogLineResult> listOfLineResults =
+ result.getListOfResults();
+
+ {
+ LogLineResult resultOne = listOfLineResults.get(0);
+ // verify that all fields in this class are parsed as expected
+ assertEquals("Cluster name not parsed properly",
+ "clusterone", resultOne.getClusterName());
+ assertEquals("Method Name not parsed properly",
+ "chooseUnderReplicatedBlocks", resultOne.getLogMethod());
+ assertEquals("Log Level not parsed properly",
+ "INFO", resultOne.getLogLevel());
+ assertEquals("event_count not parsed properly",
+ "1", resultOne.getEventCount());
+ assertEquals("ip address not parsed properly",
+ "192.168.1.1", resultOne.getIpAddress());
+ assertEquals("component type not parsed properly",
+ "hdfs_namenode", resultOne.getComponentType());
+ assertEquals("sequence number not parsed properly",
+ "10584", resultOne.getSequenceNumber());
+ assertEquals("log file path not parsed properly",
+ "/var/log/hadoop/hdfs/hadoop-hdfs-namenode-c6401.ambari.apache.org.log", resultOne.getLogFilePath());
+ assertEquals("log src file name not parsed properly",
+ "UnderReplicatedBlocks.java", resultOne.getSourceFile());
+ assertEquals("log src line number not parsed properly",
+ "394", resultOne.getSourceFileLineNumber());
+ assertEquals("host name not parsed properly",
+ "c6401.ambari.apache.org", resultOne.getHostName());
+ assertEquals("log message not parsed properly",
+ "chooseUnderReplicatedBlocks selected 2 blocks at priority level 0; Total=2 Reset bookmarks? false", resultOne.getLogMessage());
+ assertEquals("logger name not parsed properly",
+ "BlockStateChange", resultOne.getLoggerName());
+ assertEquals("id not parsed properly",
+ "9c5562fb-123f-47c8-aaf5-b5e407326c08", resultOne.getId());
+ assertEquals("message MD5 not parsed properly",
+ "-3892769501348410581", resultOne.getMessageMD5());
+ assertEquals("log time not parsed properly",
+ "1458148749036", resultOne.getLogTime());
+ assertEquals("event MD5 not parsed properly",
+ "1458148749036-2417481968206345035", resultOne.getEventMD5());
+ assertEquals("logfile line number not parsed properly",
+ "2084", resultOne.getLogFileLineNumber());
+ assertEquals("ttl not parsed properly",
+ "+7DAYS", resultOne.getTtl());
+ assertEquals("expire at not parsed properly",
+ "1458753550322", resultOne.getExpirationTime());
+ assertEquals("version not parsed properly",
+ "1528979784023932928", resultOne.getVersion());
+ }
+
+ {
+ LogLineResult resultTwo = listOfLineResults.get(1);
+ // verify second log line record's data is parsed correctly
+ assertEquals("Cluster name not parsed properly",
+ "clusterone", resultTwo.getClusterName());
+ assertEquals("Method Name not parsed properly",
+ "putMetrics", resultTwo.getLogMethod());
+ assertEquals("Log Level not parsed properly",
+ "WARN", resultTwo.getLogLevel());
+ assertEquals("event_count not parsed properly",
+ "1", resultTwo.getEventCount());
+ assertEquals("ip address not parsed properly",
+ "192.168.1.1", resultTwo.getIpAddress());
+ assertEquals("component type not parsed properly",
+ "yarn_resourcemanager", resultTwo.getComponentType());
+ assertEquals("sequence number not parsed properly",
+ "10583", resultTwo.getSequenceNumber());
+ assertEquals("log file path not parsed properly",
+ "/var/log/hadoop-yarn/yarn/yarn-yarn-resourcemanager-c6401.ambari.apache.org.log", resultTwo.getLogFilePath());
+ assertEquals("log src file name not parsed properly",
+ "HadoopTimelineMetricsSink.java", resultTwo.getSourceFile());
+ assertEquals("log src line number not parsed properly",
+ "262", resultTwo.getSourceFileLineNumber());
+ assertEquals("host name not parsed properly",
+ "c6401.ambari.apache.org", resultTwo.getHostName());
+ assertEquals("log message not parsed properly",
+ "Unable to send metrics to collector by address:http://c6401.ambari.apache.org:6188/ws/v1/timeline/metrics", resultTwo.getLogMessage());
+ assertEquals("logger name not parsed properly",
+ "timeline.HadoopTimelineMetricsSink", resultTwo.getLoggerName());
+ assertEquals("id not parsed properly",
+ "8361c5a9-5b1c-4f44-bc8f-4c6f07d94228", resultTwo.getId());
+ assertEquals("message MD5 not parsed properly",
+ "5942185045779825717", resultTwo.getMessageMD5());
+ assertEquals("log time not parsed properly",
+ "1458148746937", resultTwo.getLogTime());
+ assertEquals("event MD5 not parsed properly",
+ "14581487469371427138486123628676", resultTwo.getEventMD5());
+ assertEquals("logfile line number not parsed properly",
+ "549", resultTwo.getLogFileLineNumber());
+ assertEquals("ttl not parsed properly",
+ "+7DAYS", resultTwo.getTtl());
+ assertEquals("expire at not parsed properly",
+ "1458753550322", resultTwo.getExpirationTime());
+ assertEquals("version not parsed properly",
+ "1528979784022884357", resultTwo.getVersion());
+ }
+
+ }
+
+}