Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-boot-admin
Project
Overview
Details
Activity
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
openSource
spring-boot-admin
Commits
b034099c
Commit
b034099c
authored
Jul 24, 2018
by
赵天增
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
啦啦啦
parent
c2ccd6dd
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
134 additions
and
41 deletions
+134
-41
application.yml
monitor-core/src/main/resources/application.yml
+29
-0
AdminServerAutoConfiguration.java
...oot/admin/server/config/AdminServerAutoConfiguration.java
+5
-0
ServicesList.java
...de/codecentric/boot/admin/server/notify/ServicesList.java
+22
-0
ApplicationsController.java
...centric/boot/admin/server/web/ApplicationsController.java
+78
-41
No files found.
monitor-core/src/main/resources/application.yml
View file @
b034099c
...
@@ -15,3 +15,32 @@ management:
...
@@ -15,3 +15,32 @@ management:
endpoint
:
endpoint
:
health
:
health
:
show-details
:
ALWAYS
show-details
:
ALWAYS
# 微服务列表,如果服务不存在会触发邮件提醒
spring
:
boot
:
admin
:
notify
:
mail
:
enabled
:
true
to
:
tianzeng.zhao@medtap.cn
from
:
tianzeng.zhao@medtap.cn
services
:
YJY-APPLICATION-USER,
YJY-APPLICATION-COMMON,
YJY-APPLICATION-WECHAT,
YJY-APPLICATION-PAYMENT,
YJY-APPLICATION-SERVICE,
YJY-APPLICATION-THIRD,
YJY-APPLICATION-DOCTOR,
YJY-APPLICATION-OPERATION,
YJY-APPLICATION-TRADE,
YJY-APPLICATION-SHOP,
YJY-APPLICATION-CRM,
OPERATION-API,
USER-API,
PROMOTION-API,
RESOURCE-API,
ITEM-API,
BABABABBABA
spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/config/AdminServerAutoConfiguration.java
View file @
b034099c
...
@@ -21,6 +21,7 @@ import de.codecentric.boot.admin.server.domain.entities.SnapshottingInstanceRepo
...
@@ -21,6 +21,7 @@ import de.codecentric.boot.admin.server.domain.entities.SnapshottingInstanceRepo
import
de.codecentric.boot.admin.server.domain.events.InstanceEvent
;
import
de.codecentric.boot.admin.server.domain.events.InstanceEvent
;
import
de.codecentric.boot.admin.server.eventstore.InMemoryEventStore
;
import
de.codecentric.boot.admin.server.eventstore.InMemoryEventStore
;
import
de.codecentric.boot.admin.server.eventstore.InstanceEventStore
;
import
de.codecentric.boot.admin.server.eventstore.InstanceEventStore
;
import
de.codecentric.boot.admin.server.notify.ServicesList
;
import
de.codecentric.boot.admin.server.services.EndpointDetectionTrigger
;
import
de.codecentric.boot.admin.server.services.EndpointDetectionTrigger
;
import
de.codecentric.boot.admin.server.services.EndpointDetector
;
import
de.codecentric.boot.admin.server.services.EndpointDetector
;
import
de.codecentric.boot.admin.server.services.HashingInstanceUrlIdGenerator
;
import
de.codecentric.boot.admin.server.services.HashingInstanceUrlIdGenerator
;
...
@@ -74,6 +75,10 @@ public class AdminServerAutoConfiguration {
...
@@ -74,6 +75,10 @@ public class AdminServerAutoConfiguration {
}
}
@Bean
@Bean
public
ServicesList
servicesList
(){
return
new
ServicesList
();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingBean
public
InstanceIdGenerator
instanceIdGenerator
()
{
public
InstanceIdGenerator
instanceIdGenerator
()
{
return
new
HashingInstanceUrlIdGenerator
();
return
new
HashingInstanceUrlIdGenerator
();
...
...
spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/ServicesList.java
0 → 100644
View file @
b034099c
package
de
.
codecentric
.
boot
.
admin
.
server
.
notify
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.core.env.Environment
;
import
org.springframework.stereotype.Component
;
import
javax.validation.constraints.Max
;
import
java.util.List
;
@Component
public
class
ServicesList
{
@Autowired
private
Environment
env
;
public
List
<
String
>
getServices
()
{
return
env
.
getProperty
(
"spring.boot.admin.services"
,
List
.
class
);
}
}
spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/web/ApplicationsController.java
View file @
b034099c
...
@@ -20,20 +20,11 @@ import de.codecentric.boot.admin.server.domain.entities.Instance;
...
@@ -20,20 +20,11 @@ import de.codecentric.boot.admin.server.domain.entities.Instance;
import
de.codecentric.boot.admin.server.domain.values.BuildVersion
;
import
de.codecentric.boot.admin.server.domain.values.BuildVersion
;
import
de.codecentric.boot.admin.server.domain.values.StatusInfo
;
import
de.codecentric.boot.admin.server.domain.values.StatusInfo
;
import
de.codecentric.boot.admin.server.eventstore.InstanceEventPublisher
;
import
de.codecentric.boot.admin.server.eventstore.InstanceEventPublisher
;
import
de.codecentric.boot.admin.server.notify.ServicesList
;
import
de.codecentric.boot.admin.server.services.InstanceRegistry
;
import
de.codecentric.boot.admin.server.services.InstanceRegistry
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
reactor.util.function.Tuple2
;
import
reactor.util.function.Tuples
;
import
java.time.Duration
;
import
java.time.Instant
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.codec.ServerSentEvent
;
import
org.springframework.http.codec.ServerSentEvent
;
...
@@ -41,6 +32,14 @@ import org.springframework.web.bind.annotation.DeleteMapping;
...
@@ -41,6 +32,14 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
reactor.util.function.Tuple2
;
import
reactor.util.function.Tuples
;
import
java.time.Duration
;
import
java.time.Instant
;
import
java.util.*
;
import
static
java
.
util
.
Comparator
.
naturalOrder
;
import
static
java
.
util
.
Comparator
.
naturalOrder
;
import
static
java
.
util
.
stream
.
Collectors
.
toList
;
import
static
java
.
util
.
stream
.
Collectors
.
toList
;
...
@@ -55,7 +54,7 @@ public class ApplicationsController {
...
@@ -55,7 +54,7 @@ public class ApplicationsController {
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
ApplicationsController
.
class
);
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
ApplicationsController
.
class
);
private
static
final
ServerSentEvent
<?>
PING
=
ServerSentEvent
.
builder
().
comment
(
"ping"
).
build
();
private
static
final
ServerSentEvent
<?>
PING
=
ServerSentEvent
.
builder
().
comment
(
"ping"
).
build
();
private
static
final
Flux
<
ServerSentEvent
<?>>
PING_FLUX
=
Flux
.
interval
(
Duration
.
ZERO
,
Duration
.
ofSeconds
(
10L
))
private
static
final
Flux
<
ServerSentEvent
<?>>
PING_FLUX
=
Flux
.
interval
(
Duration
.
ZERO
,
Duration
.
ofSeconds
(
10L
))
.
map
(
tick
->
PING
);
.
map
(
tick
->
PING
);
private
final
InstanceRegistry
registry
;
private
final
InstanceRegistry
registry
;
private
final
InstanceEventPublisher
eventPublisher
;
private
final
InstanceEventPublisher
eventPublisher
;
...
@@ -64,6 +63,10 @@ public class ApplicationsController {
...
@@ -64,6 +63,10 @@ public class ApplicationsController {
this
.
eventPublisher
=
eventPublisher
;
this
.
eventPublisher
=
eventPublisher
;
}
}
@Autowired
private
ServicesList
servicesList
;
@GetMapping
(
path
=
"/applications"
,
produces
=
MediaType
.
APPLICATION_JSON_VALUE
)
@GetMapping
(
path
=
"/applications"
,
produces
=
MediaType
.
APPLICATION_JSON_VALUE
)
public
Flux
<
Application
>
applications
()
{
public
Flux
<
Application
>
applications
()
{
Flux
<
Application
>
applicationFlux
=
registry
.
getInstances
()
Flux
<
Application
>
applicationFlux
=
registry
.
getInstances
()
...
@@ -71,29 +74,64 @@ public class ApplicationsController {
...
@@ -71,29 +74,64 @@ public class ApplicationsController {
.
groupBy
(
instance
->
instance
.
getRegistration
().
getName
())
.
groupBy
(
instance
->
instance
.
getRegistration
().
getName
())
.
flatMap
(
grouped
->
toApplication
(
grouped
.
key
(),
grouped
));
.
flatMap
(
grouped
->
toApplication
(
grouped
.
key
(),
grouped
));
List
<
String
>
appNames
=
new
ArrayList
<>();
applicationFlux
.
subscribe
(
application
->
appNames
.
add
(
application
.
getName
()));
for
(
String
appName
:
minus
(
servicesList
.
getServices
(),
appNames
))
{
Application
group
=
new
Application
(
appName
.
toUpperCase
());
group
.
setStatus
(
"OFFINE"
);
group
.
setInstances
(
Collections
.
EMPTY_LIST
);
applicationFlux
=
applicationFlux
.
concatWithValues
(
group
);
}
return
applicationFlux
;
return
applicationFlux
;
}
}
/**
* 求两数组的差集
*
* @param arr1 模板数组
* @param arr2 比较数组
* @return
*/
public
static
String
[]
minus
(
List
<
String
>
arr1
,
List
<
String
>
arr2
)
{
LinkedList
<
String
>
list
=
new
LinkedList
<>();
LinkedList
<
String
>
history
=
new
LinkedList
<>();
for
(
String
str
:
arr1
)
{
if
(!
list
.
contains
(
str
.
toUpperCase
()))
{
list
.
add
(
str
.
toUpperCase
());
}
}
for
(
String
str
:
arr2
)
{
list
.
remove
(
str
.
toUpperCase
());
}
String
[]
result
=
{};
return
list
.
toArray
(
result
);
}
@GetMapping
(
path
=
"/applications"
,
produces
=
MediaType
.
TEXT_EVENT_STREAM_VALUE
)
@GetMapping
(
path
=
"/applications"
,
produces
=
MediaType
.
TEXT_EVENT_STREAM_VALUE
)
public
Flux
<
ServerSentEvent
<
Application
>>
applicationsStream
()
{
public
Flux
<
ServerSentEvent
<
Application
>>
applicationsStream
()
{
return
Flux
.
from
(
eventPublisher
)
return
Flux
.
from
(
eventPublisher
)
.
flatMap
(
event
->
registry
.
getInstance
(
event
.
getInstance
()))
.
flatMap
(
event
->
registry
.
getInstance
(
event
.
getInstance
()))
.
map
(
this
::
getApplicationForInstance
)
.
map
(
this
::
getApplicationForInstance
)
.
flatMap
(
group
->
toApplication
(
group
.
getT1
(),
group
.
getT2
()))
.
flatMap
(
group
->
toApplication
(
group
.
getT1
(),
group
.
getT2
()))
.
map
(
application
->
ServerSentEvent
.
builder
(
application
).
build
())
.
map
(
application
->
ServerSentEvent
.
builder
(
application
).
build
())
.
mergeWith
(
ping
());
.
mergeWith
(
ping
());
}
}
@DeleteMapping
(
path
=
"/applications/{name}"
)
@DeleteMapping
(
path
=
"/applications/{name}"
)
public
Mono
<
ResponseEntity
<
Void
>>
unregister
(
@PathVariable
(
"name"
)
String
name
)
{
public
Mono
<
ResponseEntity
<
Void
>>
unregister
(
@PathVariable
(
"name"
)
String
name
)
{
log
.
debug
(
"Unregister application with name '{}'"
,
name
);
log
.
debug
(
"Unregister application with name '{}'"
,
name
);
return
registry
.
getInstances
(
name
)
return
registry
.
getInstances
(
name
)
.
flatMap
(
instance
->
registry
.
deregister
(
instance
.
getId
()))
.
flatMap
(
instance
->
registry
.
deregister
(
instance
.
getId
()))
.
collectList
()
.
collectList
()
.
map
(
.
map
(
deregistered
->
!
deregistered
.
isEmpty
()
?
ResponseEntity
.
noContent
().
build
()
:
ResponseEntity
deregistered
->
!
deregistered
.
isEmpty
()
?
ResponseEntity
.
noContent
().
build
()
:
ResponseEntity
.
notFound
()
.
notFound
()
.
build
());
.
build
());
}
}
protected
Tuple2
<
String
,
Flux
<
Instance
>>
getApplicationForInstance
(
Instance
instance
)
{
protected
Tuple2
<
String
,
Flux
<
Instance
>>
getApplicationForInstance
(
Instance
instance
)
{
...
@@ -107,8 +145,7 @@ public class ApplicationsController {
...
@@ -107,8 +145,7 @@ public class ApplicationsController {
group
.
setInstances
(
instanceList
);
group
.
setInstances
(
instanceList
);
group
.
setBuildVersion
(
getBuildVersion
(
instanceList
));
group
.
setBuildVersion
(
getBuildVersion
(
instanceList
));
Tuple2
<
String
,
Instant
>
status
=
getStatus
(
instanceList
);
Tuple2
<
String
,
Instant
>
status
=
getStatus
(
instanceList
);
// group.setStatus(status.getT1());
group
.
setStatus
(
status
.
getT1
());
group
.
setStatus
(
"UP"
);
group
.
setStatusTimestamp
(
status
.
getT2
());
group
.
setStatusTimestamp
(
status
.
getT2
());
return
group
;
return
group
;
});
});
...
@@ -116,11 +153,11 @@ public class ApplicationsController {
...
@@ -116,11 +153,11 @@ public class ApplicationsController {
protected
BuildVersion
getBuildVersion
(
List
<
Instance
>
instances
)
{
protected
BuildVersion
getBuildVersion
(
List
<
Instance
>
instances
)
{
List
<
BuildVersion
>
versions
=
instances
.
stream
()
List
<
BuildVersion
>
versions
=
instances
.
stream
()
.
map
(
Instance:
:
getBuildVersion
)
.
map
(
Instance:
:
getBuildVersion
)
.
filter
(
Objects:
:
nonNull
)
.
filter
(
Objects:
:
nonNull
)
.
distinct
()
.
distinct
()
.
sorted
()
.
sorted
()
.
collect
(
toList
());
.
collect
(
toList
());
if
(
versions
.
isEmpty
())
{
if
(
versions
.
isEmpty
())
{
return
null
;
return
null
;
}
else
if
(
versions
.
size
()
==
1
)
{
}
else
if
(
versions
.
size
()
==
1
)
{
...
@@ -133,8 +170,8 @@ public class ApplicationsController {
...
@@ -133,8 +170,8 @@ public class ApplicationsController {
protected
Tuple2
<
String
,
Instant
>
getStatus
(
List
<
Instance
>
instances
)
{
protected
Tuple2
<
String
,
Instant
>
getStatus
(
List
<
Instance
>
instances
)
{
//TODO: Correct is just a second readmodel for groups
//TODO: Correct is just a second readmodel for groups
Map
<
String
,
Instant
>
statusWithTime
=
instances
.
stream
()
Map
<
String
,
Instant
>
statusWithTime
=
instances
.
stream
()
.
collect
(
toMap
(
instance
->
instance
.
getStatusInfo
().
getStatus
(),
.
collect
(
toMap
(
instance
->
instance
.
getStatusInfo
().
getStatus
(),
Instance:
:
getStatusTimestamp
,
this
::
getMax
));
Instance:
:
getStatusTimestamp
,
this
::
getMax
));
if
(
statusWithTime
.
size
()
==
1
)
{
if
(
statusWithTime
.
size
()
==
1
)
{
Map
.
Entry
<
String
,
Instant
>
e
=
statusWithTime
.
entrySet
().
iterator
().
next
();
Map
.
Entry
<
String
,
Instant
>
e
=
statusWithTime
.
entrySet
().
iterator
().
next
();
return
Tuples
.
of
(
e
.
getKey
(),
e
.
getValue
());
return
Tuples
.
of
(
e
.
getKey
(),
e
.
getValue
());
...
@@ -142,20 +179,20 @@ public class ApplicationsController {
...
@@ -142,20 +179,20 @@ public class ApplicationsController {
if
(
statusWithTime
.
containsKey
(
StatusInfo
.
STATUS_UP
))
{
if
(
statusWithTime
.
containsKey
(
StatusInfo
.
STATUS_UP
))
{
Instant
oldestNonUp
=
statusWithTime
.
entrySet
()
Instant
oldestNonUp
=
statusWithTime
.
entrySet
()
.
stream
()
.
stream
()
.
filter
(
e
->
!
StatusInfo
.
STATUS_UP
.
equals
(
e
.
getKey
()))
.
filter
(
e
->
!
StatusInfo
.
STATUS_UP
.
equals
(
e
.
getKey
()))
.
map
(
Map
.
Entry
::
getValue
)
.
map
(
Map
.
Entry
::
getValue
)
.
min
(
naturalOrder
())
.
min
(
naturalOrder
())
.
orElse
(
Instant
.
EPOCH
);
.
orElse
(
Instant
.
EPOCH
);
Instant
latest
=
getMax
(
oldestNonUp
,
statusWithTime
.
getOrDefault
(
StatusInfo
.
STATUS_UP
,
Instant
.
EPOCH
));
Instant
latest
=
getMax
(
oldestNonUp
,
statusWithTime
.
getOrDefault
(
StatusInfo
.
STATUS_UP
,
Instant
.
EPOCH
));
return
Tuples
.
of
(
StatusInfo
.
STATUS_RESTRICTED
,
latest
);
return
Tuples
.
of
(
StatusInfo
.
STATUS_RESTRICTED
,
latest
);
}
}
return
statusWithTime
.
entrySet
()
return
statusWithTime
.
entrySet
()
.
stream
()
.
stream
()
.
min
(
Map
.
Entry
.
comparingByKey
(
StatusInfo
.
severity
()))
.
min
(
Map
.
Entry
.
comparingByKey
(
StatusInfo
.
severity
()))
.
map
(
e
->
Tuples
.
of
(
e
.
getKey
(),
e
.
getValue
()))
.
map
(
e
->
Tuples
.
of
(
e
.
getKey
(),
e
.
getValue
()))
.
orElse
(
Tuples
.
of
(
StatusInfo
.
STATUS_UNKNOWN
,
Instant
.
EPOCH
));
.
orElse
(
Tuples
.
of
(
StatusInfo
.
STATUS_UNKNOWN
,
Instant
.
EPOCH
));
}
}
private
Instant
getMax
(
Instant
t1
,
Instant
t2
)
{
private
Instant
getMax
(
Instant
t1
,
Instant
t2
)
{
...
...
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