Commit 75afae26 by Johannes Stelzer

use HEAD-request to determine logfile availability

parent 5181156d
......@@ -55,12 +55,10 @@ angular.module('springBootAdmin.services', ['ngResource'])
});
}
this.getLogfile = function(app) {
return $http.get(app.url + '/logfile').success(function(response) {
return $http.head(app.url + '/logfile').success(function(response) {
app.providesLogfile = true;
app.urlLogfile = app.url + '/logfile';
}).error(function() {
app.providesLogfile = false;
app.urlLogfile = null;
});
}
}])
......
......@@ -4,8 +4,7 @@
<table class="table table-striped">
<thead>
<tr>
<th>Application</th>
<th>URL</th>
<th>Application / URL</th>
<th>Version</th>
<th>Info</th>
<th>Status</th>
......@@ -14,14 +13,13 @@
</thead>
<tbody>
<tr ng-repeat="application in applications track by application.id">
<td>{{ application.name }}</td>
<td>{{ application.url }}</td>
<td>{{ application.name }}<br/><span class="muted">{{ application.url }}</span></td>
<td>{{ application.version }}</td>
<td><span ng-repeat="(name, value) in application.info track by name">{{name}}: {{value}}<br></span></td>
<td><span class="status-{{application.status}}">{{ application.status }}</span></td>
<td>
<div class="btn-group pull-right" ng-hide="application.status == null || application.status == 'OFFLINE'">
<a ng-disabled="!application.providesLogfile" target="_self" class="btn btn-success" ng-href="{{application.urlLogfile}}"><i class="icon-file icon-white"></i>Log</a>
<a ng-disabled="!application.providesLogfile" target="_self" class="btn btn-success" ng-href="{{application.providesLogfile ? application.url + '/logfile' :''}}"><i class="icon-file icon-white"></i>Log</a>
<a ui-sref="apps.details.metrics({id: application.id})" class="btn btn-success">Details</a>
<a ui-sref="apps.logging({id: application.id})" class="btn btn-success">Logging</a>
<a ui-sref="apps.jmx({id: application.id})" class="btn btn-success">JMX</a>
......
......@@ -21,51 +21,71 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Controller that provides an API for logfiles, i.e. downloading the main logfile configured in environment property
* 'logging.file' that is standard, but optional property for spring-boot applications.
*/
@Controller
@RestController
public class LogfileController {
private static final Logger LOGGER = LoggerFactory.getLogger(LogfileController.class);
@Autowired
private Environment env;
@Value("${logging.file}")
private String logfile;
@RequestMapping("/logfile")
@ResponseBody
@RequestMapping(value = "/logfile", method = { RequestMethod.GET })
public String getLogfile(HttpServletResponse response) {
String path = env.getProperty("logging.file");
if (path == null) {
if (logfile == null) {
LOGGER.error("Logfile download failed for missing property 'logging.file'");
response.setStatus(HttpStatus.NOT_FOUND.value());
return "Logfile download failed for missing property 'logging.file'";
}
Resource file = new FileSystemResource(path);
Resource file = new FileSystemResource(logfile);
if (!file.exists()) {
LOGGER.error("Logfile download failed for missing file at path=" + path);
return "Logfile download failed for missing file at path=" + path;
LOGGER.error("Logfile download failed for missing file at path={}", logfile);
response.setStatus(HttpStatus.NOT_FOUND.value());
return "Logfile download failed for missing file at path=" + logfile;
}
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getFilename() + "\"");
try {
FileCopyUtils.copy(file.getInputStream(), response.getOutputStream());
} catch (IOException e) {
LOGGER.error("Logfile download failed for path=" + path);
return "Logfile download failed for path=" + path;
} catch (IOException ex) {
LOGGER.error("Logfile download failed for path={}. Reasond: {}", logfile, ex.getMessage());
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return "Logfile download failed for path=" + logfile;
}
return null;
}
@RequestMapping(value = "/logfile", method = { RequestMethod.HEAD })
public ResponseEntity<?> hasLogfile() {
if (logfile == null) {
return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
}
Resource file = new FileSystemResource(logfile);
if (!file.exists()) {
return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<Void>(HttpStatus.OK);
}
public void setLogfile(String logfile) {
this.logfile = logfile;
}
}
package de.codecentric.boot.admin.controller;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import org.junit.Test;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.FileCopyUtils;
public class LogfileControllerTest {
private LogfileController controller = new LogfileController();
@Test
public void logfile_noProperty() {
assertEquals(HttpStatus.NOT_FOUND, controller.hasLogfile().getStatusCode());
MockHttpServletResponse response = new MockHttpServletResponse();
controller.getLogfile(response);
assertEquals(HttpStatus.NOT_FOUND.value(), response.getStatus());
}
@Test
public void logfile_noFile() {
controller.setLogfile("does_not_exist.log");
assertEquals(HttpStatus.NOT_FOUND, controller.hasLogfile().getStatusCode());
MockHttpServletResponse response = new MockHttpServletResponse();
controller.getLogfile(response);
assertEquals(HttpStatus.NOT_FOUND.value(), response.getStatus());
}
@Test
public void logfile() throws IOException {
try {
FileCopyUtils.copy("--TEST--".getBytes(), new File("test.log"));
controller.setLogfile("test.log");
assertEquals(HttpStatus.OK, controller.hasLogfile().getStatusCode());
MockHttpServletResponse response = new MockHttpServletResponse();
controller.getLogfile(response);
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertEquals("--TEST--", response.getContentAsString());
} finally {
new File("test.log").delete();
}
}
}
......@@ -74,4 +74,22 @@ public class SpringBootAdminRegistratorTest {
assertFalse(result);
}
@Test
public void register_failed_conflict() {
AdminProperties adminProps = new AdminProperties();
adminProps.setUrl("http://sba:8080");
AdminClientProperties clientProps = new AdminClientProperties();
clientProps.setUrl("http://localhost:8080");
clientProps.setName("AppName");
RestTemplate restTemplate = mock(RestTemplate.class);
when(restTemplate.postForEntity(isA(String.class), isA(Application.class), eq(Application.class))).thenReturn(
new ResponseEntity<Application>(HttpStatus.CONFLICT));
SpringBootAdminRegistrator registrator = new SpringBootAdminRegistrator(restTemplate, adminProps, clientProps);
boolean result = registrator.register();
assertFalse(result);
}
}
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