/*
* Copyright 2010-2012 Amazon Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://aws.amazon.com/apache2.0
*
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and
* limitations under the License.
*/
package com.amazonaws.eclipse.elasticbeanstalk.server.ui.configEditor;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.wst.server.ui.editor.ServerEditorSection;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.eclipse.core.HttpClientFactory;
import com.amazonaws.eclipse.elasticbeanstalk.ElasticBeanstalkPlugin;
import com.amazonaws.eclipse.elasticbeanstalk.Environment;
import com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalk;
import com.amazonaws.services.elasticbeanstalk.model.EnvironmentInfoDescription;
import com.amazonaws.services.elasticbeanstalk.model.RequestEnvironmentInfoRequest;
import com.amazonaws.services.elasticbeanstalk.model.RetrieveEnvironmentInfoRequest;
import com.amazonaws.services.elasticbeanstalk.model.RetrieveEnvironmentInfoResult;
public class LogTailEditorSection extends ServerEditorSection {
/** The section widget we're managing */
private Section section;
private FormToolkit toolkit;
private Text log;
private static final Object JOB_FAMILY = new Object();
@Override
public void createSection(Composite parent) {
super.createSection(parent);
toolkit = getFormToolkit(parent.getDisplay());
section = toolkit.createSection(parent,
Section.TITLE_BAR | Section.DESCRIPTION );
section.setText("Environment Log");
section.setDescription("Aggregate logs of your Elastic Beanstalk environment");
Composite composite = toolkit.createComposite(section);
FillLayout layout = new FillLayout();
layout.marginHeight = 10;
layout.marginWidth = 10;
layout.type = SWT.VERTICAL;
composite.setLayout(layout);
toolkit.paintBordersFor(composite);
section.setClient(composite);
section.setLayout(layout);
createLogViewer(composite);
refresh();
}
/**
* @param composite
*/
private void createLogViewer(Composite composite) {
log = new Text(composite, SWT.READ_ONLY | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
}
private class LoadEnvironmentLogJob extends Job {
private final Environment environment;
public LoadEnvironmentLogJob(Environment environment) {
super("Loading log for environment " + environment.getEnvironmentName());
this.environment = environment;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
AWSElasticBeanstalk elasticBeanstalk = AwsToolkitCore.getClientFactory(environment.getAccountId())
.getElasticBeanstalkClientByEndpoint(environment.getRegionEndpoint());
try {
elasticBeanstalk.requestEnvironmentInfo(new RequestEnvironmentInfoRequest().withEnvironmentName(
environment.getEnvironmentName()).withInfoType("tail"));
} catch (AmazonServiceException ase) {
if (ase.getErrorCode().equals("InvalidParameterValue")) {
return Status.OK_STATUS;
} else {
throw ase;
}
}
RetrieveEnvironmentInfoResult infoResult;
long pollingStartTime = System.currentTimeMillis();
while (true) {
infoResult = elasticBeanstalk.retrieveEnvironmentInfo(
new RetrieveEnvironmentInfoRequest()
.withInfoType("tail")
.withEnvironmentName(environment.getEnvironmentName()));
// Break once we find environment info
if (infoResult.getEnvironmentInfo().size() > 0) {
break;
}
// Or if we don't see any env info after waiting a while
if (System.currentTimeMillis() - pollingStartTime > 1000*60*5) {
break;
}
// Otherwise, keep polling
try {Thread.sleep(1000 * 5);}
catch (InterruptedException e) { return Status.CANCEL_STATUS; }
}
final List<EnvironmentInfoDescription> envInfos = infoResult.getEnvironmentInfo();
DefaultHttpClient client = HttpClientFactory.create(
ElasticBeanstalkPlugin.getDefault(),
"https://s3.amazonaws.com");
DefaultHttpRequestRetryHandler retryhandler = new DefaultHttpRequestRetryHandler(3, true);
client.setHttpRequestRetryHandler(retryhandler);
// For each instance, there are potentially multiple tail samples.
// We just display the last one for each instance.
Map<String, EnvironmentInfoDescription> tails = new HashMap<String, EnvironmentInfoDescription>();
for (EnvironmentInfoDescription envInfo : envInfos) {
if ( !tails.containsKey(envInfo.getEc2InstanceId())
|| tails.get(envInfo.getEc2InstanceId()).getSampleTimestamp()
.before(envInfo.getSampleTimestamp()) ) {
tails.put(envInfo.getEc2InstanceId(), envInfo);
}
}
List<String> instanceIds = new ArrayList<String>();
instanceIds.addAll(tails.keySet());
Collections.sort(instanceIds);
// Print the id and the log for each instance
final StringBuilder builder = new StringBuilder();
for ( String instanceId : instanceIds ) {
builder.append("Log for ").append(instanceId).append(":").append("\n\n");
EnvironmentInfoDescription envInfo = tails.get(instanceId);
// The message is a url to fetch for logs
HttpGet rq = new HttpGet(envInfo.getMessage());
try {
HttpResponse response = client.execute(rq);
InputStream content = response.getEntity().getContent();
builder.append(IOUtils.toString(content));
} catch ( Exception e ) {
builder.append("Exception fetching " + envInfo.getMessage());
}
}
Display.getDefault().syncExec(new Runnable() {
public void run() {
log.setText(builder.toString());
}
});
return Status.OK_STATUS;
}
@Override
public boolean belongsTo(Object family) {
return family == JOB_FAMILY;
}
}
/**
* Refreshes the log.
*/
void refresh() {
/*
* There's a race condition here, but the consequences are trivial.
*/
if ( Job.getJobManager().find(JOB_FAMILY).length == 0 ) {
Environment environment = (Environment) server.loadAdapter(Environment.class, null);
new LoadEnvironmentLogJob(environment).schedule();
}
}
}