frankchen021 / bithon Goto Github PK
View Code? Open in Web Editor NEWAn observability platform mainly for Java
License: Apache License 2.0
An observability platform mainly for Java
License: Apache License 2.0
jedis provides requestTime/response respectively, it adds some complexity for implementation. And from users' side, they usually don't care about how long a command is sent to server and how long it takes to return the response, instead, they care about how long a client command complets.
And it's hard to provide such response time for some client libs such as lettuce which utilizes async operations heavily.
This issue tracks the merge of current requestTime/responseTime together as a new responseTime
it's convenient when debugging without deleting the -javaagent argument to disable the agent
Currently, all refresh requires reload ALL data in given intervals. This should be improved by loading data incrementally.
To do this, the chart component at client side should holds a timestamp when it load data last time.
Currently, targetHost and targetUri are stored together as URL, it's best to separate host and uri so that it provides flexible ways to query.
Current Kafka collector requires metric messages in array format, which limits the extensibility of Bithon to easily support messages come from 3rd systems.
This issues describes how we plan to solve it:
for Kafka collector:
SizedIterator
objectfor kafka sink,
it serialize an array of metric object as described in scenario 2 above.
For 3rd systems, it usually sends a single metric object in a single kafka message as described in scenario 1 above.
For example, with the support of GROUP-BY semantics, metrics of young gc and full gc could be put on one chart.
Currently, all interceptors are loaded in a separated class loader. This works well except involving shading libraries.
For underlying communication such as thrift, we're now using version 0.14 the latest at the moment, but some apps are using older versions such as 0.11. Since thrift is not shaded and much difficult for us to shade the generated code and communicate layer code, there would be version conflicts.
A better way to solve it is to implement a agent class loader which loads all classes required by agent. Once this class loader is provided, the shading module could also be eliminated which would be a little easier to build and maintain this project.
2021-04-11 11:53:54.810 [Agent WARN] - [main:AopLogger] Error occurred during invoking LoggerCallAppenders.after()
java.lang.NoClassDefFoundError: ch/qos/logback/classic/spi/ILoggingEvent
at com.sbss.bithon.agent.plugin.logback.interceptor.LoggerCallAppenders.onMethodLeave(LoggerCallAppenders.java:41)
at com.sbss.bithon.agent.boot.aop.AroundMethodAop.intercept(AroundMethodAop.java:79)
at com.sbss.bithon.agent.boot.aop.MethodAop.intercept(MethodAop.java:47)
at ch.qos.logback.classic.Logger.callAppenders(Logger.java)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:421)
at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
at ch.qos.logback.classic.Logger.log(Logger.java:765)
at com.alibaba.druid.support.logging.SLF4JImpl.info(SLF4JImpl.java:72)
at com.alibaba.druid.pool.DruidDataSource.init$original$pmpVFQl2(DruidDataSource.java:1002)
at com.alibaba.druid.pool.DruidDataSource.init$original$pmpVFQl2$accessor$UqqJrtCB(DruidDataSource.java)
at com.alibaba.druid.pool.DruidDataSource$auxiliary$O0MTLNRK.invoke(Unknown Source)
at com.sbss.bithon.agent.boot.aop.AroundMethodAop.intercept(AroundMethodAop.java:64)
at com.sbss.bithon.agent.boot.aop.MethodAop.intercept(MethodAop.java:47)
at com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1311)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1307)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:109)
at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.lambda$h2Console$0(H2ConsoleAutoConfiguration.java:72)
at org.springframework.beans.factory.ObjectProvider.ifAvailable(ObjectProvider.java:93)
at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.h2Console(H2ConsoleAutoConfiguration.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:637)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1176)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:211)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:202)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:96)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:85)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:255)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:229)
at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:53)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5166)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:843)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:440)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:193)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:178)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:158)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at com.sbss.bithon.server.starter.StarterApplication.main(StarterApplication.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
to replace file queue
For URL like
http://dev.discovery.bithon.cn/eureka/apps/DEMO/172.16.1.1:demo:8080
applying customized rule, it could be folded into
http://dev.discovery.bithon.cn/eureka/apps/{appName}
or
http://dev.discovery.bithon.cn/eureka/apps/DEMO/{instance}
Current redis-metrics show request/response time by SUM aggregation, avg/min/max aggregations are better
ERROR 51824 --- [pool-4-thread-5] c.s.b.s.c.sink.local.LocalMetricSink : No Handler for message [mongo-metrics]
These two names are confusing.
Introduced by #61
Current jvm metrics contains several metric categories such as CPU/Memory/Thread. Since the message format of thrift is defined to reflect these categories, it introduces some differences compared to other metrics, which causes code difference in ThriftMetricCollector
This issue propose to flatten the metric definition in thrift to unify the metric processing code pattern
sun.net.NetworkClient
public void openServer(String server, int port)
throws IOException, UnknownHostException {
if (serverSocket != null)
closeServer();
serverSocket = doConnect (server, port);
try {
serverOutput = new PrintStream(new BufferedOutputStream(
serverSocket.getOutputStream()),
true, encoding);
} catch (UnsupportedEncodingException e) {
throw new InternalError(encoding +"encoding not found", e);
}
serverInput = new BufferedInputStream(serverSocket.getInputStream());
}
Currently, to develop a new metric, we have to do 4 things as below:
sendxxx
method to thrift/gRPC interfaceThriftMessageConverters
to convert user defined object to thrift/gRPC defined messagesAlthough thrift/gRPC has provided a high efficient ways to transport metrics from client to server , current way is still not friendly for agent development.
To change that , a new generic metrics binary format is proposed as below.
The reason why new format is still binary instead of something like JSON is that it has the highest performance and lest bytes transmitted on network, especially for metrics like http call and request which usually have large records for high QPS systems.
In the modern days, there're many binary serialization format we could choose. One is AVRO.
But since the pattern of metrics is the same(what's different is the number of dimensions and metrics), and we don't want to generate serialization/deserialization code based on predefined schema(If schema is needed at agent side, why not we still use the current thrift way ?) , it's better to provide customer defined message format.
For 3rd systems that will be integrated, the customized message format is not a burden because it's always recommended to support these 3rd systems at server side.
Every time the client send a batch of metrics with different dimension values to server.
Type | Value |
---|---|
string | data source name |
list< string > | schema |
list< MetricSet > | metricSets |
A metric-set is composed of a timestamp, a set of dimensions, a set of metric values. Types of all dimensions are string.
Type | Value |
---|---|
long | timestamp |
list < string > | dimensions |
list < MetricValue > | metrics |
A metric value stores the actual value for a metric. There're 2 types of metric value now:
Histogram
.A TLV scheme is used to serialize metric value to binary. And for (long/double) value encoding , ZigZag
is applied.
The table below lists the value of T field of a MetricValue. A byte is enough to represent this field.
T | Meaning |
---|---|
1 | Long |
2 | Double |
3 | Histogram |
Since the format does not contain any names of dimensions/metrics, a schema is still needed at collector side as it does now.
The schema is used when turning this binary format into a generic MetricSet
object which is based on a HashMap
.
It's important to have ttl defined for metrics so that number of records won't be grown too large.
And TTL could be configured for each data source
Currently, menu items are built through MetricSidebar
client component. There're some problems:
So, it's better to define menu items at client side only.
Similar to #34
Although there will be one more message from client to server, it would unify and simplify message processing at server side
[lettuce-nioEventLoop-4-2:RedisAsyncCommandComplete] after completeResult AsyncCommandInterceptor
...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.