-
Notifications
You must be signed in to change notification settings - Fork 3
Home
The most effective way to use Cereebro is by coupling it with Spring Cloud and Netflix OSS : Get started with Cereebro, Spring Cloud Netflix and the Eureka Server
Cereebro is made of two parts :
- Cereebro Snitch : an "agent" installed on every application, that snitches on the component and its relationship with others
- Cereebro Server : reads the information provided by all the snitches in the system, and aggregates them to reconstitute the whole component graph
-
Component
: The base unit of a system : application, database, cache, file... for the moment only the minimal component attributes are managed (name + type) -
ComponentRelationships
: aComponent
and its relationships with others (Dependency
orConsumer
components)
On the client side (Snitch) :
-
RelationshipDetector
: analyses the internals of an application to detect relationships with other components -
Snitch
: reveals information on aComponent
and its relationships by usingRelationshipDetector
s -
SystemFragment
: a portion of a given system, revealed from aSnitch
's point of view
On the server side :
-
SnitchRegistry
: holds a registry ofSnitch
intances -
System
: The big picture, consisting of allComponent
s and their relationships -
SystemResolver
: browses aSnitchRegistry
to build the dependency graph of aSystem
A Cereebro Snitch consists of two things :
- a unique URI that can be accessed somehow
- providing a
SystemFragment
, either as a Java object or JSON
Each of your application should be enhanced with the Cereebro Snitch so it can publish information about its relationships.
We provide Spring Boot and Spring Cloud starters to speed things up.
Out of the box cereebro-snitch-spring-boot-starter
adds the following features to your application :
- detect automatically :
- SQL databases (MySQL, Oracle, DB2, MSSQL...)
- Apache Cassandra databases
- Redis clusters
- MongoDB databases
- Elasticsearch connections
- Neo4j databases
- RabbitMQ connections
- OAuth 2.0 authorization server (token info / user info)
- Applications downstream of a Zuul proxy
- LDAP servers
- detect beans annotated with Cereebro annotations :
@DependencyHint
,@ConsumerHint
or@RelationshipHints
- detect relationships declared in application properties
- provide an actuator
Snitch
endpoint that will reveal your applications relationships
When using Spring Cloud Netflix, which we highly recommend for micro-service architectures, we add :
- detect
@FeignClient
annotated beans as dependencies - detect dependencies to a Eureka Server
- populate Eureka metadata with the Snitch endpoint URI and JSON
SystemFragment
You could implement your own Snitch
without Spring if you wanted to, as the cereebro-core
modules does not depend on Spring.
It would probably make you rewrite most of the relationship detection features though, as ours rely on the Spring Context and Spring Boot's conditional features.
The RelationshipDetector
interface is in charge of analyzing some kind of application relationship.
Cereebro provides the following implementations by default :
-
DataSourceRelationshipDetector
: RDBMS dependencies -
CassandraRelationshipDetector
: Apache Cassandra dependencies -
FeignClientAnnotationRelationshipDetector
: HTTP service dependencies -
RabbitRelationshipDetector
: RabbitMQ dependencies -
ElasticSearchRelationshipDetector
: Elasticsearch dependencies -
EurekaServerRelationshipDetector
: Eureka Server dependencies -
MongoDbRelationshipDetector
: MongoDB dependencies -
Neo4jRelationshipDetector
: Neo4j dependencies -
RedisRelationshipDetector
: Redis dependencies -
AuthorizationServerRelationshipDetector
: OAuth 2.0 authorization server dependencies -
ZuulRouteRelationshipDetector
: Dependencies to applications proxied by Zuul -
LdapRelationshipDetector
: LDAP server dependencies -
ConsumerHintAnnotationRelationshipDetector
: Detect annotated beans as consumers -
DependencyHintAnnotationRelationshipDetector
: Detect annotated beans as dependencies -
RelationshipHintsAnnotationRelationshipDetector
: Detect multiple relationships -
ConfigurationPropertiesRelationshipDetector
: Detect relationships from Cereebro properties
Note that configuration properties should be used as a last resort for dependencies.
You should try to document dependencies by annotating beans and configuration classes with Cereebro annotations, because everything your application depends on should be materialized by some bean.
Consumers are not known by the application most of the times, but if these consumers cary the Cereebro Snitch, the Cereebro server will be able to reconstitute the relationship from the other side.
One valid case for relying on properties is to document a consumer outside the scope of the system.
To detect new types of components, you can provide your own implementations of RelationshipDetector
and declare them as Spring beans. For annotation based detection, you can extend AnnotationRelationshipDetector<T>
.
The Cereebro Snitch endpoint aggregates the results of all relationship detector instances in the Spring context.
Detectors can be customized or deactivated with properties, see the configuration options for more info.
We welcome contributions to the cereebro-snitch
module for technologies supported by Spring Boot and Spring Cloud.
Some relationships cannot be detected automatically by us. For example, you may consume an HTTP API using tools like Spring's RestTemplate
,
in which case there is no way we can guess the name of the component your application depends on.
We have create Cereebro annotations to document your Spring @Configuration
classes, @Bean
factory methods or @Component
classes.
:
-
@DependencyHint
declares aDependency
on a component -
@ConsumerHint
declares a component that is aConsumer
of the application -
@RelationshipHints
allows you to declare multiple dependency and consumer hints at once
Most of the time, you should be only documenting dependencies as they are always "materialized" by some bean or configuration. Consumers can be retrieved the other way around : if component A is a consumer of component B, then component B is a dependency of component A. The Cereebro server will resolve the dependencies of both components, and figure out the consumer relationship.
Example on a configuration class factory method :
@Bean
@DependencyHint(name = "twitter-api", type = "application/http")
public TwitterApiClient client(RestOperations restTemplate) {
return new TwitterApiClientImpl(restTemplate);
}
Example on a configuration class that brings multiple relationships :
@Configuration
@Import({ ExternalConfigurationClassThatConfiguresManyRelationships.class })
@RelationshipHints(
dependencies = {
@DependencyHint(name = "some-web-service", type = "application/http"),
@DependencyHint(name = "some-database", type = "database/whatever")
},
consumers = {
@ConsumerHint(name = "mobile-application", type = "application/mobile" )
})
public class ExternalImportConfiguration {
// ...
}
Example on a Spring @Component
class (@Service
, @Repository
, @Controller
...) :
@Component
@DependencyHint(name = "google-maps-api", type = "application/http")
public class TrackingService {
// ...
}
If you write a client library for your API, you can put the annotation directly on your interface, so that any bean implementing your interface will be picked up by our detectors :
/** Note : you only need cereebro-core on the classpath */
@DependencyHint(name = "my-api", type = "application/http")
public interface MyApiClient {
// ...
}
The Snitch Endpoint is a Spring Boot actuator endpoint that publishes the relationships information detected.
It can be accessed by default at /cereebro/snitch
. This path is relative to the actuator, see the Spring Boot documentation for more.
Typical output looks like this JSON SystemFragment
:
{
"componentRelationships":[
{
"component":{
"name":"my-application",
"type":"application/http"
},
"dependencies":[
{
"component":{
"name":"some_mysql_schema",
"type":"database/relational"
}
},
{
"component":{
"name":"some-api",
"type":"application/http"
}
}
],
"consumers":[
{
"component":{
"name":"android-app",
"type":"application/mobile/android"
}
}
]
}
]
}
When using Spring Cloud Netflix, Cereebro will populate Eureka metadata upon registration with the Eureka Server.
The following metadata keys are set by the EurekaMetadataPopulator
:
-
io.cereebro.snitch.uri
: The Snitch absolute URI -
io.cereebro.snitch.system-fragment-json
: String containing aSystemFragment
serialized as JSON
The Cereebro Server processes the system fragment directly, the URI is here to identify the Snitch (and also "just in case").
By default, EurekaMetadataPopulator
uses the same logic as spring-cloud-netflix to to determine the hostname and port, see EurekaInstanceConfigBean#getHostname(boolean)
.
Like they do for the health and info endpoints, we allow you to override the declared Snitch URI with two mutually exclusive properties (EurekaInstanceSnitchProperties
) :
# The absolute path of the Snitch endpoint
# This setting will take precedence over the relative path if both are set.
# Use this if the actuator runs on a different port than the application server,
# or if you want to register an https url.
cereebro.snitch.eureka.endpoint-url=
# The relative path of the Snitch endpoint
# This path is relative to the hostname determined using EurekaInstanceConfigBean.
# Use this setting if the actuator runs on the same port as the application server,
# but either the application or the actuator (or both) have a specific context-path.
cereebro.snitch.eureka.endpoint-url-path=
You can switch off Eureka metadata population by setting cereebro.snitch.eureka.enabled
to false
.
For command line or installed applications, you can either log the SystemFragment on application startup or write it to a file (see the application properties section). You could run the application with one of these options during tests, or just once manually.
You can then make these files available to your Cereebro Server, and use them to complete your component graph with cereebro.server.snitch.resources=classpath:xxx.json
(see Cereebro Server properties for more info).
# The host application component name
# Defaults to the value of ${spring.application.name) (preferred),
# or a random string if none is set
cereebro.application.component.name=
# The host application component type
cereebro.application.component.type=application/http
# Dependency components, will be added to the ones detected programmatically
cereebro.application.dependencies[0].component.name
cereebro.application.dependencies[0].component.type
# Consumer components
cereebro.application.consumers[0].component.name
cereebro.application.consumers[0].component.type
# Log the SystemFragment on startup
cereebro.snitch.log-on-startup=false
# Write the SystemFragment to a file on startup
cereebro.snitch.file.enabled=false
# File location, temporary file by default
# (the location of the temp file will be logged)
cereebro.snitch.file.location=
########################
# Detectors
########################
# Rabbit MQ
cereebro.snitch.detect.rabbit.enabled=true
# Cassandra
cereebro.snitch.detect.cassandra.enabled=true
# Eureka
cereebro.snitch.detect.eureka.enabled=true
cereebro.snitch.detect.eureka.default-name=eureka-server
# JDBC DataSource
cereebro.snitch.detect.jdbc.enabled=true
cereebro.snitch.detect.jdbc.default-name=default_db
# Mongo DB
cereebro.snitch.detect.mongo.enabled=true
# Neo4j
cereebro.snitch.detect.neo4j.enabled=true
cereebro.snitch.detect.neo4j.default-name=default
# OAuth 2.0
cereebro.snitch.detect.oauth2.authorization-server.enabled=true
cereebro.snitch.detect.oauth2.authorization-server.default-name=oauth2-authorization-server
# Redis
cereebro.snitch.detect.redis.enabled=true
cereebro.snitch.detect.redis.default-name=default
# Zuul routes
cereebro.snitch.detect.zuul.enabled=true
# LDAP
cereebro.snitch.detect.ldap.enabled=true
cereebro.snitch.detect.ldap.default-name=default
Note that when using yaml, consumers and dependencies should be defined as arrays :
cereebro:
application:
dependencies:
-
component:
name: xxx
type: yyy
consumers:
-
component:
name: aaa
type: bbb
CereebroSnitchMvcEndpoint
properties :
# Relative path of the actuator endpoint
endpoints.cereebro.path=/cereebro/snitch
# Enable the actuator endpoint
endpoints.cereebro.enabled=true
# Whether the actuator endpoint is considered sensitive
# (See Spring Boot docs for more information)
endpoints.cereebro.sensitive=true
The Cereebro Server is an aggregator of snitched information.
It must know the location of every Snitch
in the system through its SnitchRegistry
.
Out of the box cereebro-server-spring-boot-starter
allows you to target a fixed set of JSON resources (on the file system, classpath, HTTP...) through configuration properties, for example :
cereebro:
server:
system:
name: your system name
snitch:
resources:
- 'classpath:/snitches/some-fragment-of-my-system.json'
- 'file:///somewhere/other-part-of-my-system.json'
You should only use a static list of Snitch resources to document applications that cannot be analyzed dynamically, for example installed applications (mobile, desktop...) or short lived processes (batch, tasks...).
The most powerful way to use Cereebro is along with Spring Cloud, Netflix OSS and the Eureka Server. The Eureka Server is a perfect Snitch registry because it should know every application in your system.
See how to get started.
If you are not using Spring Cloud, you could target manually each application's Snitch endpoint from your Eureka server :
cereebro:
server:
system:
name: your system name
snitch:
resources:
- 'http://first-application/cereebro/snitch'
- 'http://second-application/cereebro/snitch'
- 'http://third-application/cereebro/snitch'
This approach is somewhat limited, especially in a micro-service architecture where components come by the dozen.
Services may also have various security mechanisms to secure their Snitch endpoint, which we don't handle at this time (Spring's UrlResource
does not handle curl style HTTP Basic credentials http://user:password@hostname
).
The Cereebro Server browses SnitchRegistry
instances to access each Snitch
.
If you find a different way to discover information about components and their relationships,
you can implement your own Snitch
and declare a new Spring Bean implementing SnitchRegistry
in your Cereebro Server application.
This is basically what our own starters do : by making your Cereebro Server a Eureka Client, we activate a configuration class that declares a DiscoveryClientSnitchRegistry
bean.
For example, Zipkin takes another angle on how to discover relationships between micro-services at runtime (tracing). Zipkin's API could very well be adapted as a Cereebro Snitch
.
We may support Consul in the near feature (the only problem being that it has poor metadata support).
The Cereebro Server offers a basic UI at /cereebro/system
.
This same resource can also be consumed as a JSON/HTTP API by adding a header (Accept: application/json
) or appending .json
at the end of the path.
You can build your UI by consuming this resource and creating your own view, either on the Cereebro Server using Spring MVC, or from a separate web application of yours.
From the Cereebro Server you can indeed use the Java API directly.
To retrieve the System
object provided by the HTTP API, you can get a SystemService
instance injected from the Spring Context.
By default, the system is resolved everytime the page is opened.
For large production systems, caching can be added in standard Spring fashion.
See the Spring Boot documentation to configure a cache manager using your favorite tool.
DefaultSystemService#get
is annotated with @CacheResult
, meaning that the resolved System
will be cached if a CacheManager
is available in the Spring Context. The cache is named io.cereebro.system
.
# Display name of your system
cereebro.server.system.name=cereebro
# Relative path of the system resource (JSON/HTML)
cereebro.server.system.path=/cereebro/system
# Fixed list of Spring org.springframework.core.io.Resource that produce SystemFragment JSON
# Use comma separated strings for properties files, or an array for yaml
cereebro.server.system.snitch.resources=
See the whole change log.
Mapping with Spring versions :
Cereebro | Spring Boot | Spring Cloud |
---|---|---|
0.0.1 | 1.4.5.RELEASE | Camden.SR6 |
0.0.2 | 1.4.5.RELEASE | Camden.SR6 |
0.0.3 | 1.4.5.RELEASE | Camden.SR6 |
0.0.4 | 1.4.5.RELEASE | Camden.SR6 |
1.0.0 | 1.4.5.RELEASE | Camden.SR6 |
1.1.0 | 1.4.5.RELEASE | Camden.SR6 |
1.2.0 | 1.5.4.RELEASE | Dalston.SR1 |
1.2.1 | 1.5.4.RELEASE | Dalston.SR1 |
1.2.2 | 1.5.6.RELEASE | Dalston.SR2 |
1.2.3 | 1.5.6.RELEASE | Dalston.SR2 |