Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
3c013322
Commit
3c013322
authored
Jul 02, 2016
by
Phillip Webb
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'gh-5670'
Closes gh-5670
parents
b732aeb4
2583a534
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
586 additions
and
283 deletions
+586
-283
EndpointDocumentation.java
...mework/boot/actuate/hypermedia/EndpointDocumentation.java
+11
-6
EndpointWebMvcManagementContextConfiguration.java
...nfigure/EndpointWebMvcManagementContextConfiguration.java
+8
-0
AbstractMvcEndpoint.java
...mework/boot/actuate/endpoint/mvc/AbstractMvcEndpoint.java
+113
-0
DocsMvcEndpoint.java
...gframework/boot/actuate/endpoint/mvc/DocsMvcEndpoint.java
+5
-63
HalJsonMvcEndpoint.java
...amework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java
+4
-69
HeapdumpMvcEndpoint.java
...mework/boot/actuate/endpoint/mvc/HeapdumpMvcEndpoint.java
+233
-0
JolokiaMvcEndpoint.java
...amework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java
+3
-65
LogFileMvcEndpoint.java
...amework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java
+4
-62
EndpointWebMvcAutoConfigurationTests.java
...e/autoconfigure/EndpointWebMvcAutoConfigurationTests.java
+2
-2
HalBrowserMvcEndpointDisabledIntegrationTests.java
...nt/mvc/HalBrowserMvcEndpointDisabledIntegrationTests.java
+1
-1
HalBrowserMvcEndpointVanillaIntegrationTests.java
...int/mvc/HalBrowserMvcEndpointVanillaIntegrationTests.java
+1
-1
HeapdumpMvcEndpointTests.java
...k/boot/actuate/endpoint/mvc/HeapdumpMvcEndpointTests.java
+171
-0
production-ready-features.adoc
...oot-docs/src/main/asciidoc/production-ready-features.adoc
+30
-14
No files found.
spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/EndpointDocumentation.java
View file @
3c013322
...
...
@@ -20,12 +20,15 @@ import java.io.File;
import
java.io.FileOutputStream
;
import
java.io.PrintWriter
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.HashSet
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
groovy.text.Template
;
import
groovy.text.TemplateEngine
;
...
...
@@ -70,6 +73,9 @@ public class EndpointDocumentation {
static
final
File
LOG_FILE
=
new
File
(
"target/logs/spring.log"
);
private
static
final
Set
<
String
>
SKIPPED
=
Collections
.<
String
>
unmodifiableSet
(
new
HashSet
<
String
>(
Arrays
.
asList
(
"/docs"
,
"/logfile"
,
"/heapdump"
)));
@Autowired
private
MvcEndpoints
mvcEndpoints
;
...
...
@@ -103,28 +109,27 @@ public class EndpointDocumentation {
@Test
public
void
endpoints
()
throws
Exception
{
final
File
docs
=
new
File
(
"src/main/asciidoc"
);
final
Map
<
String
,
Object
>
model
=
new
LinkedHashMap
<
String
,
Object
>();
final
List
<
EndpointDoc
>
endpoints
=
new
ArrayList
<
EndpointDoc
>();
model
.
put
(
"endpoints"
,
endpoints
);
for
(
MvcEndpoint
endpoint
:
getEndpoints
())
{
final
String
endpointPath
=
StringUtils
.
hasText
(
endpoint
.
getPath
())
?
endpoint
.
getPath
()
:
"/"
;
if
(!
endpointPath
.
equals
(
"/docs"
)
&&
!
endpointPath
.
equals
(
"/logfile"
))
{
final
String
endpointPath
=
(
StringUtils
.
hasText
(
endpoint
.
getPath
())
?
endpoint
.
getPath
()
:
"/"
);
if
(!
SKIPPED
.
contains
(
endpointPath
))
{
String
output
=
endpointPath
.
substring
(
1
);
output
=
output
.
length
()
>
0
?
output
:
"./"
;
this
.
mockMvc
.
perform
(
get
(
endpointPath
).
accept
(
MediaType
.
APPLICATION_JSON
))
.
andExpect
(
status
().
isOk
()).
andDo
(
document
(
output
))
.
andDo
(
new
ResultHandler
()
{
@Override
public
void
handle
(
MvcResult
mvcResult
)
throws
Exception
{
EndpointDoc
endpoint
=
new
EndpointDoc
(
docs
,
endpointPath
);
endpoints
.
add
(
endpoint
);
}
});
}
}
...
...
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.java
View file @
3c013322
...
...
@@ -31,6 +31,7 @@ import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import
org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer
;
import
org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint
;
import
org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint
;
import
org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint
;
import
org.springframework.boot.actuate.endpoint.mvc.LogFileMvcEndpoint
;
import
org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint
;
import
org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint
;
...
...
@@ -132,6 +133,13 @@ public class EndpointWebMvcManagementContextConfiguration {
return
new
EnvironmentMvcEndpoint
(
delegate
);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
(
"heapdump"
)
public
HeapdumpMvcEndpoint
heapdumpMvcEndpoint
()
{
return
new
HeapdumpMvcEndpoint
();
}
@Bean
@ConditionalOnBean
(
HealthEndpoint
.
class
)
@ConditionalOnEnabledEndpoint
(
"health"
)
...
...
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractMvcEndpoint.java
0 → 100644
View file @
3c013322
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
endpoint
.
mvc
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Pattern
;
import
org.springframework.boot.actuate.endpoint.Endpoint
;
import
org.springframework.boot.actuate.endpoint.EndpointProperties
;
import
org.springframework.context.EnvironmentAware
;
import
org.springframework.core.env.Environment
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
;
/**
* Abstract base class for {@link MvcEndpoint} implementations without a backing
* {@link Endpoint}.
*
* @author Phillip Webb
* @author Lari Hotari
* @since 1.4.0
*/
public
abstract
class
AbstractMvcEndpoint
extends
WebMvcConfigurerAdapter
implements
MvcEndpoint
,
EnvironmentAware
{
private
Environment
environment
;
/**
* Endpoint URL path.
*/
@NotNull
@Pattern
(
regexp
=
"/.*|^$"
,
message
=
"Path must start with /"
)
private
String
path
;
/**
* Enable the endpoint.
*/
private
Boolean
enabled
;
/**
* Mark if the endpoint exposes sensitive information.
*/
private
Boolean
sensitive
;
private
final
boolean
sensitiveDefault
;
public
AbstractMvcEndpoint
(
String
path
,
boolean
sensitive
)
{
this
.
path
=
path
;
this
.
sensitiveDefault
=
sensitive
;
}
public
AbstractMvcEndpoint
(
String
path
,
boolean
sensitive
,
boolean
enabled
)
{
this
.
path
=
path
;
this
.
sensitiveDefault
=
sensitive
;
this
.
enabled
=
enabled
;
}
@Override
public
void
setEnvironment
(
Environment
environment
)
{
this
.
environment
=
environment
;
}
protected
final
Environment
getEnvironment
()
{
return
this
.
environment
;
}
@Override
public
String
getPath
()
{
return
this
.
path
;
}
public
void
setPath
(
String
path
)
{
this
.
path
=
path
;
}
public
boolean
isEnabled
()
{
return
EndpointProperties
.
isEnabled
(
this
.
environment
,
this
.
enabled
);
}
public
void
setEnabled
(
Boolean
enabled
)
{
this
.
enabled
=
enabled
;
}
@Override
public
boolean
isSensitive
()
{
return
EndpointProperties
.
isSensitive
(
this
.
environment
,
this
.
sensitive
,
this
.
sensitiveDefault
);
}
public
void
setSensitive
(
Boolean
sensitive
)
{
this
.
sensitive
=
sensitive
;
}
@Override
@SuppressWarnings
(
"rawtypes"
)
public
Class
<?
extends
Endpoint
>
getEndpointType
()
{
return
null
;
}
}
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/DocsMvcEndpoint.java
View file @
3c013322
...
...
@@ -16,15 +16,10 @@
package
org
.
springframework
.
boot
.
actuate
.
endpoint
.
mvc
;
import
org.springframework.boot.actuate.endpoint.Endpoint
;
import
org.springframework.boot.actuate.endpoint.EndpointProperties
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.context.EnvironmentAware
;
import
org.springframework.core.env.Environment
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
;
/**
* {@link MvcEndpoint} to expose actuator documentation.
...
...
@@ -33,95 +28,42 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @since 1.3.0
*/
@ConfigurationProperties
(
"endpoints.docs"
)
public
class
DocsMvcEndpoint
extends
WebMvcConfigurerAdapter
implements
MvcEndpoint
,
EnvironmentAware
{
public
class
DocsMvcEndpoint
extends
AbstractMvcEndpoint
{
private
static
final
String
DOCS_LOCATION
=
"classpath:/META-INF/resources/spring-boot-actuator/docs/"
;
private
Environment
environment
;
/**
* Endpoint URL path.
*/
private
String
path
=
"/docs"
;
/**
* Enable the endpoint.
*/
private
boolean
enabled
=
true
;
/**
* Mark if the endpoint exposes sensitive information.
*/
private
Boolean
sensitive
;
private
final
ManagementServletContext
managementServletContext
;
private
Curies
curies
=
new
Curies
();
@Override
public
void
setEnvironment
(
Environment
environment
)
{
this
.
environment
=
environment
;
}
public
Curies
getCuries
()
{
return
this
.
curies
;
}
public
DocsMvcEndpoint
(
ManagementServletContext
managementServletContext
)
{
super
(
"/docs"
,
false
);
this
.
managementServletContext
=
managementServletContext
;
}
@RequestMapping
(
value
=
"/"
,
produces
=
MediaType
.
TEXT_HTML_VALUE
)
public
String
browse
()
{
return
"forward:"
+
this
.
managementServletContext
.
getContextPath
()
+
this
.
path
return
"forward:"
+
this
.
managementServletContext
.
getContextPath
()
+
getPath
()
+
"/index.html"
;
}
@RequestMapping
(
value
=
""
,
produces
=
MediaType
.
TEXT_HTML_VALUE
)
public
String
redirect
()
{
return
"redirect:"
+
this
.
managementServletContext
.
getContextPath
()
+
this
.
path
return
"redirect:"
+
this
.
managementServletContext
.
getContextPath
()
+
getPath
()
+
"/"
;
}
@Override
public
void
addResourceHandlers
(
ResourceHandlerRegistry
registry
)
{
registry
.
addResourceHandler
(
this
.
managementServletContext
.
getContextPath
()
+
this
.
path
+
"/**"
)
this
.
managementServletContext
.
getContextPath
()
+
getPath
()
+
"/**"
)
.
addResourceLocations
(
DOCS_LOCATION
);
}
public
void
setPath
(
String
path
)
{
this
.
path
=
path
;
}
@Override
public
String
getPath
()
{
return
this
.
path
;
}
public
boolean
isEnabled
()
{
return
this
.
enabled
;
}
public
void
setEnabled
(
boolean
enabled
)
{
this
.
enabled
=
enabled
;
}
@Override
public
boolean
isSensitive
()
{
return
EndpointProperties
.
isSensitive
(
this
.
environment
,
this
.
sensitive
,
false
);
}
public
void
setSensitive
(
Boolean
sensitive
)
{
this
.
sensitive
=
sensitive
;
}
@Override
public
Class
<?
extends
Endpoint
<?>>
getEndpointType
()
{
return
null
;
}
/**
* Properties of the default CurieProvider (used for adding docs links). If enabled,
* all unqualified rels will pick up a prefix and a curie template pointing to the
...
...
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java
View file @
3c013322
...
...
@@ -16,20 +16,12 @@
package
org
.
springframework
.
boot
.
actuate
.
endpoint
.
mvc
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Pattern
;
import
org.springframework.boot.actuate.endpoint.Endpoint
;
import
org.springframework.boot.actuate.endpoint.EndpointProperties
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.context.EnvironmentAware
;
import
org.springframework.core.env.Environment
;
import
org.springframework.hateoas.ResourceSupport
;
import
org.springframework.http.MediaType
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
;
/**
* {@link MvcEndpoint} to expose HAL-formatted JSON.
...
...
@@ -40,41 +32,16 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @since 1.3.0
*/
@ConfigurationProperties
(
"endpoints.actuator"
)
public
class
HalJsonMvcEndpoint
extends
WebMvcConfigurerAdapter
implements
MvcEndpoint
,
EnvironmentAware
{
private
Environment
environment
;
/**
* Endpoint URL path.
*/
@NotNull
@Pattern
(
regexp
=
"^$|/.*"
,
message
=
"Path must be empty or start with /"
)
private
String
path
;
/**
* Enable the endpoint.
*/
private
boolean
enabled
=
true
;
/**
* Mark if the endpoint exposes sensitive information.
*/
private
Boolean
sensitive
;
public
class
HalJsonMvcEndpoint
extends
AbstractMvcEndpoint
{
private
final
ManagementServletContext
managementServletContext
;
public
HalJsonMvcEndpoint
(
ManagementServletContext
managementServletContext
)
{
super
(
getDefaultPath
(
managementServletContext
),
false
);
this
.
managementServletContext
=
managementServletContext
;
this
.
path
=
getDefaultPath
(
managementServletContext
);
}
@Override
public
void
setEnvironment
(
Environment
environment
)
{
this
.
environment
=
environment
;
}
private
String
getDefaultPath
(
ManagementServletContext
managementServletContext
)
{
private
static
String
getDefaultPath
(
ManagementServletContext
managementServletContext
)
{
if
(
StringUtils
.
hasText
(
managementServletContext
.
getContextPath
()))
{
return
""
;
}
...
...
@@ -87,39 +54,7 @@ public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter
return
new
ResourceSupport
();
}
public
void
setPath
(
String
path
)
{
this
.
path
=
path
;
}
@Override
public
String
getPath
()
{
return
this
.
path
;
}
public
boolean
isEnabled
()
{
return
this
.
enabled
;
}
public
void
setEnabled
(
boolean
enabled
)
{
this
.
enabled
=
enabled
;
}
@Override
public
boolean
isSensitive
()
{
return
EndpointProperties
.
isSensitive
(
this
.
environment
,
this
.
sensitive
,
false
);
}
public
void
setSensitive
(
Boolean
sensitive
)
{
this
.
sensitive
=
sensitive
;
}
@Override
public
Class
<?
extends
Endpoint
<?>>
getEndpointType
()
{
return
null
;
}
protected
final
ManagementServletContext
getManagementServletContext
()
{
return
this
.
managementServletContext
;
}
}
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HeapdumpMvcEndpoint.java
0 → 100644
View file @
3c013322
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
endpoint
.
mvc
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.lang.management.ManagementFactory
;
import
java.lang.management.PlatformManagedObject
;
import
java.lang.reflect.Method
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.locks.Lock
;
import
java.util.concurrent.locks.ReentrantLock
;
import
java.util.zip.GZIPOutputStream
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.lang.UsesJava7
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.util.ReflectionUtils
;
import
org.springframework.util.StreamUtils
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.ResponseStatus
;
/**
* {@link MvcEndpoint} to expose heap dumps.
*
* @author Lari Hotari
* @author Phillip Webb
* @since 1.4.0
*/
@ConfigurationProperties
(
"endpoints.heapdump"
)
@HypermediaDisabled
public
class
HeapdumpMvcEndpoint
extends
AbstractMvcEndpoint
implements
MvcEndpoint
{
private
final
long
timeout
;
private
final
Lock
lock
=
new
ReentrantLock
();
private
HeapDumper
heapDumper
;
public
HeapdumpMvcEndpoint
()
{
this
(
TimeUnit
.
SECONDS
.
toMillis
(
10
));
}
protected
HeapdumpMvcEndpoint
(
long
timeout
)
{
super
(
"/heapdump"
,
true
);
this
.
timeout
=
timeout
;
}
@RequestMapping
(
method
=
RequestMethod
.
GET
,
produces
=
MediaType
.
APPLICATION_OCTET_STREAM_VALUE
)
public
void
invoke
(
@RequestParam
(
defaultValue
=
"true"
)
boolean
live
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
,
ServletException
{
if
(!
isEnabled
())
{
response
.
setStatus
(
HttpStatus
.
NOT_FOUND
.
value
());
return
;
}
try
{
if
(
this
.
lock
.
tryLock
(
this
.
timeout
,
TimeUnit
.
MILLISECONDS
))
{
try
{
dumpHeap
(
live
,
request
,
response
);
return
;
}
finally
{
this
.
lock
.
unlock
();
}
}
}
catch
(
InterruptedException
ex
)
{
// Ignore
}
response
.
setStatus
(
HttpStatus
.
TOO_MANY_REQUESTS
.
value
());
}
private
void
dumpHeap
(
boolean
live
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
,
ServletException
,
InterruptedException
{
if
(
this
.
heapDumper
==
null
)
{
this
.
heapDumper
=
createHeapDumper
();
}
File
file
=
createTempFile
(
live
);
try
{
this
.
heapDumper
.
dumpHeap
(
file
,
live
);
handle
(
file
,
request
,
response
);
}
finally
{
file
.
delete
();
}
}
private
File
createTempFile
(
boolean
live
)
throws
IOException
{
String
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd-HH-mm"
).
format
(
new
Date
());
File
file
=
File
.
createTempFile
(
"heapdump"
+
date
+
(
live
?
"-live"
:
""
),
".hprof"
);
file
.
delete
();
return
file
;
}
/**
* Factory method used to create the {@link HeapDumper}.
* @return the heap dumper to use
* @throws HeapDumperUnavailableException if the heap dumper cannot be created
*/
protected
HeapDumper
createHeapDumper
()
throws
HeapDumperUnavailableException
{
return
new
HotSpotDiagnosticMXBeanHeapDumper
();
}
/**
* Handle the heap dump file and respond. By default this method will return the
* response as a GZip stream.
* @param heapDumpFile the generated dump file
* @param request the HTTP request
* @param response the HTTP response
* @throws ServletException on servlet error
* @throws IOException on IO error
*/
protected
void
handle
(
File
heapDumpFile
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"application/octet-stream"
);
response
.
setHeader
(
"Content-Disposition"
,
"attachment; filename=\""
+
(
heapDumpFile
.
getName
()
+
".gz"
)
+
"\""
);
try
{
InputStream
in
=
new
FileInputStream
(
heapDumpFile
);
try
{
GZIPOutputStream
out
=
new
GZIPOutputStream
(
response
.
getOutputStream
());
StreamUtils
.
copy
(
in
,
out
);
out
.
finish
();
}
catch
(
NullPointerException
ex
)
{
}
finally
{
try
{
in
.
close
();
}
catch
(
Throwable
ex
)
{
}
}
}
catch
(
FileNotFoundException
ex
)
{
}
}
/**
* Strategy interface used to dump the heap to a file.
*/
protected
interface
HeapDumper
{
/**
* Dump the current heap to the specified file.
* @param file the file to dump the heap to
* @param live if only <em>live</em> objects (i.e. objects that are reachable from
* others) should be dumped
* @throws IOException on IO error
* @throws InterruptedException on thread interruption
*/
void
dumpHeap
(
File
file
,
boolean
live
)
throws
IOException
,
InterruptedException
;
}
/**
* {@link HeapDumper} that uses {@code com.sun.management.HotSpotDiagnosticMXBean}
* available on Oracle and OpenJDK to dump the heap to a file.
*/
@UsesJava7
protected
static
class
HotSpotDiagnosticMXBeanHeapDumper
implements
HeapDumper
{
private
Object
diagnosticMXBean
;
private
Method
dumpHeapMethod
;
@SuppressWarnings
(
"unchecked"
)
protected
HotSpotDiagnosticMXBeanHeapDumper
()
{
try
{
Class
<?>
diagnosticMXBeanClass
=
ClassUtils
.
resolveClassName
(
"com.sun.management.HotSpotDiagnosticMXBean"
,
null
);
this
.
diagnosticMXBean
=
ManagementFactory
.
getPlatformMXBean
(
(
Class
<
PlatformManagedObject
>)
diagnosticMXBeanClass
);
this
.
dumpHeapMethod
=
ReflectionUtils
.
findMethod
(
diagnosticMXBeanClass
,
"dumpHeap"
,
String
.
class
,
Boolean
.
TYPE
);
}
catch
(
Throwable
ex
)
{
throw
new
HeapDumperUnavailableException
(
"Unable to locate HotSpotDiagnosticMXBean"
,
ex
);
}
}
@Override
public
void
dumpHeap
(
File
file
,
boolean
live
)
{
ReflectionUtils
.
invokeMethod
(
this
.
dumpHeapMethod
,
this
.
diagnosticMXBean
,
file
.
getAbsolutePath
(),
live
);
}
}
/**
* Exception to be thrown if the {@link HeapDumper} cannot be created.
*/
@ResponseStatus
(
HttpStatus
.
SERVICE_UNAVAILABLE
)
protected
static
class
HeapDumperUnavailableException
extends
RuntimeException
{
public
HeapDumperUnavailableException
(
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
}
}
}
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java
View file @
3c013322
...
...
@@ -22,20 +22,14 @@ import javax.servlet.ServletContext;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequestWrapper
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Pattern
;
import
org.jolokia.http.AgentServlet
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.boot.actuate.endpoint.Endpoint
;
import
org.springframework.boot.actuate.endpoint.EndpointProperties
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ApplicationContextAware
;
import
org.springframework.context.EnvironmentAware
;
import
org.springframework.core.env.Environment
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.context.ServletContextAware
;
import
org.springframework.web.servlet.ModelAndView
;
...
...
@@ -50,31 +44,12 @@ import org.springframework.web.util.UrlPathHelper;
*/
@ConfigurationProperties
(
prefix
=
"endpoints.jolokia"
,
ignoreUnknownFields
=
false
)
@HypermediaDisabled
public
class
JolokiaMvcEndpoint
implements
MvcEndpoint
,
InitializingBean
,
ApplicationContextAware
,
ServletContextAware
,
EnvironmentAware
{
private
Environment
environment
;
/**
* Endpoint URL path.
*/
@NotNull
@Pattern
(
regexp
=
"/.*"
,
message
=
"Path must start with /"
)
private
String
path
=
"/jolokia"
;
/**
* Enable the endpoint.
*/
private
boolean
enabled
=
true
;
/**
* Mark if the endpoint exposes sensitive information.
*/
private
Boolean
sensitive
;
public
class
JolokiaMvcEndpoint
extends
AbstractMvcEndpoint
implements
InitializingBean
,
ApplicationContextAware
,
ServletContextAware
{
private
final
ServletWrappingController
controller
=
new
ServletWrappingController
();
public
JolokiaMvcEndpoint
()
{
super
(
"/jolokia"
,
true
);
this
.
controller
.
setServletClass
(
AgentServlet
.
class
);
this
.
controller
.
setServletName
(
"jolokia"
);
}
...
...
@@ -99,43 +74,6 @@ public class JolokiaMvcEndpoint implements MvcEndpoint, InitializingBean,
this
.
controller
.
setApplicationContext
(
context
);
}
@Override
public
void
setEnvironment
(
Environment
environment
)
{
this
.
environment
=
environment
;
}
public
boolean
isEnabled
()
{
return
this
.
enabled
;
}
public
void
setEnabled
(
boolean
enabled
)
{
this
.
enabled
=
enabled
;
}
@Override
public
boolean
isSensitive
()
{
return
EndpointProperties
.
isSensitive
(
this
.
environment
,
this
.
sensitive
,
true
);
}
public
void
setSensitive
(
Boolean
sensitive
)
{
this
.
sensitive
=
sensitive
;
}
@Override
public
String
getPath
()
{
return
this
.
path
;
}
public
void
setPath
(
String
path
)
{
this
.
path
=
path
;
}
@Override
@SuppressWarnings
(
"rawtypes"
)
public
Class
<?
extends
Endpoint
>
getEndpointType
()
{
return
null
;
}
@RequestMapping
(
"/**"
)
public
ModelAndView
handle
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
Exception
{
...
...
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java
View file @
3c013322
...
...
@@ -22,18 +22,12 @@ import java.io.IOException;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Pattern
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.boot.actuate.endpoint.Endpoint
;
import
org.springframework.boot.actuate.endpoint.EndpointProperties
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.logging.LogFile
;
import
org.springframework.context.EnvironmentAware
;
import
org.springframework.core.env.Environment
;
import
org.springframework.core.io.FileSystemResource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.http.HttpStatus
;
...
...
@@ -52,64 +46,18 @@ import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
* @since 1.3.0
*/
@ConfigurationProperties
(
prefix
=
"endpoints.logfile"
)
public
class
LogFileMvcEndpoint
implements
MvcEndpoint
,
EnvironmentAware
{
public
class
LogFileMvcEndpoint
extends
AbstractMvcEndpoint
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
LogFileMvcEndpoint
.
class
);
/**
* Endpoint URL path.
*/
@NotNull
@Pattern
(
regexp
=
"/.*"
,
message
=
"Path must start with /"
)
private
String
path
=
"/logfile"
;
/**
* Enable the endpoint.
*/
private
boolean
enabled
=
true
;
/**
* Mark if the endpoint exposes sensitive information.
*/
private
Boolean
sensitive
;
/**
* External Logfile to be accessed. Can be used if the logfile is written by output
* redirect and not by the logging-system itself.
*/
private
File
externalFile
;
private
Environment
environment
;
@Override
public
void
setEnvironment
(
Environment
environment
)
{
this
.
environment
=
environment
;
}
@Override
public
String
getPath
()
{
return
this
.
path
;
}
public
void
setPath
(
String
path
)
{
this
.
path
=
path
;
}
public
boolean
isEnabled
()
{
return
this
.
enabled
;
}
public
void
setEnabled
(
boolean
enabled
)
{
this
.
enabled
=
enabled
;
}
@Override
public
boolean
isSensitive
()
{
return
EndpointProperties
.
isSensitive
(
this
.
environment
,
this
.
sensitive
,
true
);
}
public
void
setSensitive
(
Boolean
sensitive
)
{
this
.
sensitive
=
sensitive
;
public
LogFileMvcEndpoint
()
{
super
(
"/logfile"
,
true
);
}
public
File
getExternalFile
()
{
...
...
@@ -120,12 +68,6 @@ public class LogFileMvcEndpoint implements MvcEndpoint, EnvironmentAware {
this
.
externalFile
=
externalFile
;
}
@Override
@SuppressWarnings
(
"rawtypes"
)
public
Class
<?
extends
Endpoint
>
getEndpointType
()
{
return
null
;
}
@RequestMapping
(
method
=
{
RequestMethod
.
GET
,
RequestMethod
.
HEAD
})
public
void
invoke
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
...
...
@@ -147,7 +89,7 @@ public class LogFileMvcEndpoint implements MvcEndpoint, EnvironmentAware {
if
(
this
.
externalFile
!=
null
)
{
return
new
FileSystemResource
(
this
.
externalFile
);
}
LogFile
logFile
=
LogFile
.
get
(
this
.
environment
);
LogFile
logFile
=
LogFile
.
get
(
getEnvironment
()
);
if
(
logFile
==
null
)
{
logger
.
debug
(
"Missing 'logging.file' or 'logging.path' properties"
);
return
null
;
...
...
spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java
View file @
3c013322
...
...
@@ -429,8 +429,8 @@ public class EndpointWebMvcAutoConfigurationTests {
this
.
applicationContext
.
register
(
RootConfig
.
class
,
BaseConfiguration
.
class
,
ServerPortConfig
.
class
,
EndpointWebMvcAutoConfiguration
.
class
);
this
.
applicationContext
.
refresh
();
// /health, /metrics, /env, /actuator (/shutdown is disabled by default)
assertThat
(
this
.
applicationContext
.
getBeansOfType
(
MvcEndpoint
.
class
)).
hasSize
(
4
);
// /health, /metrics, /env, /actuator
, /heapdump
(/shutdown is disabled by default)
assertThat
(
this
.
applicationContext
.
getBeansOfType
(
MvcEndpoint
.
class
)).
hasSize
(
5
);
}
@Test
...
...
spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointDisabledIntegrationTests.java
View file @
3c013322
...
...
@@ -83,7 +83,7 @@ public class HalBrowserMvcEndpointDisabledIntegrationTests {
public
void
endpointsDoNotHaveLinks
()
throws
Exception
{
for
(
MvcEndpoint
endpoint
:
this
.
mvcEndpoints
.
getEndpoints
())
{
String
path
=
endpoint
.
getPath
();
if
(
"/actuator"
.
equals
(
path
))
{
if
(
"/actuator"
.
equals
(
path
)
||
endpoint
instanceof
HeapdumpMvcEndpoint
)
{
continue
;
}
path
=
path
.
length
()
>
0
?
path
:
"/"
;
...
...
spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointVanillaIntegrationTests.java
View file @
3c013322
...
...
@@ -122,7 +122,7 @@ public class HalBrowserMvcEndpointVanillaIntegrationTests {
@Test
public
void
endpointsEachHaveSelf
()
throws
Exception
{
Set
<
String
>
collections
=
new
HashSet
<
String
>(
Arrays
.
asList
(
"/trace"
,
"/beans"
,
"/dump"
));
Arrays
.
asList
(
"/trace"
,
"/beans"
,
"/dump"
,
"/heapdump"
));
for
(
MvcEndpoint
endpoint
:
this
.
mvcEndpoints
.
getEndpoints
())
{
String
path
=
endpoint
.
getPath
();
if
(
collections
.
contains
(
path
))
{
...
...
spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HeapdumpMvcEndpointTests.java
0 → 100644
View file @
3c013322
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
endpoint
.
mvc
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.concurrent.TimeUnit
;
import
java.util.zip.GZIPInputStream
;
import
org.fusesource.hawtbuf.ByteArrayInputStream
;
import
org.junit.After
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration
;
import
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Import
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
org.springframework.test.web.servlet.MockMvc
;
import
org.springframework.test.web.servlet.MvcResult
;
import
org.springframework.test.web.servlet.setup.MockMvcBuilders
;
import
org.springframework.util.FileCopyUtils
;
import
org.springframework.web.context.WebApplicationContext
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
request
.
MockMvcRequestBuilders
.
get
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
status
;
/**
* Tests for {@link HeapdumpMvcEndpoint}.
*
* @author Phillip Webb
*/
@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
public
class
HeapdumpMvcEndpointTests
{
@Autowired
private
WebApplicationContext
context
;
private
MockMvc
mvc
;
@Autowired
private
TestHeapdumpMvcEndpoint
endpoint
;
@Before
public
void
setup
()
{
this
.
context
.
getBean
(
HeapdumpMvcEndpoint
.
class
).
setEnabled
(
true
);
this
.
mvc
=
MockMvcBuilders
.
webAppContextSetup
(
this
.
context
).
build
();
}
@After
public
void
reset
()
{
this
.
endpoint
.
reset
();
}
@Test
public
void
invokeWhenDisabledShouldReturnNotFoundStatus
()
throws
Exception
{
this
.
endpoint
.
setEnabled
(
false
);
this
.
mvc
.
perform
(
get
(
"/heapdump"
)).
andExpect
(
status
().
isNotFound
());
}
@Test
public
void
invokeWhenNotAvailableShouldReturnServiceUnavailableStatus
()
throws
Exception
{
this
.
endpoint
.
setAvailable
(
false
);
this
.
mvc
.
perform
(
get
(
"/heapdump"
)).
andExpect
(
status
().
isServiceUnavailable
());
}
@Test
public
void
invokeWhenLockedShouldReturnTooManyRequestsStatus
()
throws
Exception
{
this
.
endpoint
.
setLocked
(
true
);
this
.
mvc
.
perform
(
get
(
"/heapdump"
)).
andExpect
(
status
().
isTooManyRequests
());
}
@Test
public
void
invokeShouldReturnGzipContent
()
throws
Exception
{
MvcResult
result
=
this
.
mvc
.
perform
(
get
(
"/heapdump"
)).
andExpect
(
status
().
isOk
())
.
andReturn
();
byte
[]
bytes
=
result
.
getResponse
().
getContentAsByteArray
();
GZIPInputStream
stream
=
new
GZIPInputStream
(
new
ByteArrayInputStream
(
bytes
));
byte
[]
uncompressed
=
FileCopyUtils
.
copyToByteArray
(
stream
);
assertThat
(
uncompressed
).
isEqualTo
(
"HEAPDUMP"
.
getBytes
());
}
@Import
({
JacksonAutoConfiguration
.
class
,
HttpMessageConvertersAutoConfiguration
.
class
,
EndpointWebMvcAutoConfiguration
.
class
,
WebMvcAutoConfiguration
.
class
,
ManagementServerPropertiesAutoConfiguration
.
class
})
@Configuration
public
static
class
TestConfiguration
{
@Bean
public
HeapdumpMvcEndpoint
endpoint
()
{
return
new
TestHeapdumpMvcEndpoint
();
}
}
private
static
class
TestHeapdumpMvcEndpoint
extends
HeapdumpMvcEndpoint
{
private
boolean
available
;
private
boolean
locked
;
private
String
heapDump
;
TestHeapdumpMvcEndpoint
()
{
super
(
TimeUnit
.
SECONDS
.
toMillis
(
1
));
reset
();
}
public
void
reset
()
{
this
.
available
=
true
;
this
.
locked
=
false
;
this
.
heapDump
=
"HEAPDUMP"
;
}
@Override
protected
HeapDumper
createHeapDumper
()
{
return
new
HeapDumper
()
{
@Override
public
void
dumpHeap
(
File
file
,
boolean
live
)
throws
IOException
,
InterruptedException
{
if
(!
TestHeapdumpMvcEndpoint
.
this
.
available
)
{
throw
new
HeapDumperUnavailableException
(
"Not available"
,
null
);
}
if
(
TestHeapdumpMvcEndpoint
.
this
.
locked
)
{
throw
new
InterruptedException
();
}
FileCopyUtils
.
copy
(
TestHeapdumpMvcEndpoint
.
this
.
heapDump
.
getBytes
(),
file
);
}
};
}
public
void
setAvailable
(
boolean
available
)
{
this
.
available
=
available
;
}
public
void
setLocked
(
boolean
locked
)
{
this
.
locked
=
locked
;
}
}
}
spring-boot-docs/src/main/asciidoc/production-ready-features.adoc
View file @
3c013322
...
...
@@ -62,7 +62,7 @@ The way that endpoints are exposed will depend on the type of technology that yo
Most
applications
choose
HTTP
monitoring
,
where
the
ID
of
the
endpoint
is
mapped
to
a
URL
.
For
example
,
by
default
,
the
`
health
`
endpoint
will
be
mapped
to
`/
health
`.
The
following
endpoints
are
available
:
The
following
technology
agnostic
endpoints
are
available
:
[
cols
=
"2,5,1"
]
|===
...
...
@@ -86,11 +86,6 @@ HATEOAS to be on the classpath.
|
Displays
a
collated
list
of
all
`@
ConfigurationProperties
`.
|
true
|`
docs
`
|
Displays
documentation
,
including
example
requests
and
responses
,
for
the
Actuator
's
endpoints. Requires `spring-boot-actuator-docs` to be on the classpath.
|false
|`
dump
`
|
Performs
a
thread
dump
.
|
true
...
...
@@ -104,8 +99,9 @@ endpoints. Requires `spring-boot-actuator-docs` to be on the classpath.
|true
|`health`
|
Shows
application
health
information
(
when
the
application
is
secure
,
a
simple
'`status`'
when
accessed
over
an
unauthenticated
connection
or
full
message
details
when
authenticated
).
|Shows application health information (when the application is secure, a simple '
`
status
`
'
when accessed over an unauthenticated connection or full message details when
authenticated).
|false
|`info`
...
...
@@ -116,12 +112,6 @@ unauthenticated connection or full message details when authenticated).
|Shows any Liquibase database migrations that have been applied.
|true
|`
logfile
`
|
Returns
the
contents
of
the
logfile
(
if
`
logging
.
file
`
or
`
logging
.
path
`
properties
have
been
set
).
Only
available
via
MVC
.
Supports
the
use
of
the
HTTP
`
Range
`
header
to
retrieve
part
of
the
log
file
's content.
|true
|`metrics`
|Shows '
`
metrics
`
' information for the current application.
|true
...
...
@@ -139,6 +129,32 @@ part of the log file's content.
|true
|===
If you are using Spring MVC, the following additional endpoints can also be used:
[cols="2,5,1"]
|===
| ID | Description | Sensitive Default
|`docs`
|Displays documentation, including example requests and responses, for the Actuator'
s
endpoints
.
Requires
`
spring
-
boot
-
actuator
-
docs
`
to
be
on
the
classpath
.
|
false
|`
heapdump
`
|
Returns
a
GZip
compressed
`
hprof
`
heap
dump
file
.
|
true
|`
jolokia
`
|
Exposes
JMX
beans
over
HTTP
(
when
Jolokia
is
on
the
classpath
).
|
true
|`
logfile
`
|
Returns
the
contents
of
the
logfile
(
if
`
logging
.
file
`
or
`
logging
.
path
`
properties
have
been
set
).
Supports
the
use
of
the
HTTP
`
Range
`
header
to
retrieve
part
of
the
log
file
's
content.
|true
|===
NOTE: Depending on how an endpoint is exposed, the `sensitive` property may be used as
a security hint. For example, sensitive endpoints will require a username/password when
they are accessed over HTTP (or simply disabled if web security is not enabled).
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment