Giter Site home page Giter Site logo

zalando / opentracing-toolbox Goto Github PK

View Code? Open in Web Editor NEW
178.0 178.0 45.0 1.92 MB

Best-of-breed OpenTracing utilities, instrumentations and extensions

License: MIT License

Java 97.32% Shell 0.09% Kotlin 2.59%
http http-headers java monitoring plugin-extension spring-boot-starter tracing

opentracing-toolbox's People

Contributors

alexanderyastrebov avatar bocytko avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar epaul avatar fatroom avatar innokenty avatar jonasjurczok avatar jrehwaldt avatar karannagi avatar lukasniemeier-zalando avatar olliahonen avatar pc-alves avatar piyushmor avatar tkrop avatar vetinari avatar whiskeysierra avatar zeitlinger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

opentracing-toolbox's Issues

Could we please have some Javadocs?

At least for the public interfaces which are meant to be used by programmers, each method should have one or two sentences saying what they are doing.

(For example, I've seen the forEach and delegate methods, but I don't understand what they are supposed to be doing.)

Make Spring 5/Spring Boot 2 the default

Detailed Description

This library is compiled, build and released against Spring 4 and Spring Boot 1 by default. Support for Spring 5 and Spring Boot 2 is supported via special build profiles that are primarily used by travis.

The goal is to change the default to Spring 5 and Spring Boot 2.

Context

In the upcoming weeks, we're trying to move to Spring Boot 2 internally. It's therefore the next logical step to have all libraries support it natively.

Possible Implementation

  • change spring versions in properties section
  • rename spring5 profile to spring4
  • merge any spring4-* profiles into spring4

Support for try with resources

Tracer.start could return something AutoClosable to support try-with-resources idiom like:

try (AutoClosable x = tracer.start()) {
    // do work
}

@Scheduled doesn't work out of the box

I have a spring-boot project with tracer added (more details below). Configuration is just the default one, just the trace name is configured. I'm trying to get my trace value in a @Scheduled method, but I get IllegalStateException: X-Flow-ID has not been started.

Question: how is it supposed to work? I think the documentation on this is missing.

Description

  • I'm running on spring-boot:1.4.6.
  • I have only tracer-spring-boot-starter:0.16.0 in dependencies.
  • I have configured only this single property for tracer: tracer.traces.X-Flow-ID=flow-id
  • I have a @Scheduled method inside of which I'm calling tracer.get("X-Flow-ID").getValue() on an @Autowired Tracer tracer field.
  • Autowiring works, but I get the following exception:
java.lang.IllegalStateException: X-Flow-ID has not been started
	at org.zalando.tracer.DefaultTracer.getAndCheckValue(DefaultTracer.java:102) ~[tracer-core-0.16.0.jar:na]
	at org.zalando.tracer.DefaultTracer.access$000(DefaultTracer.java:15) ~[tracer-core-0.16.0.jar:na]
	at org.zalando.tracer.DefaultTracer$1.getValue(DefaultTracer.java:68) ~[tracer-core-0.16.0.jar:na]

Question

I didn't really find any docs of what a "support for scheduling" means. I'm sure I'm doing something wrong, but can you point out what's missing? I was expecting that the trace will be already initialized and I can just get it's value (and send in an outgoing request).

Clarify Length of Generated Trace Identifier

I think it would be worth to talk about the length (count of chars) of a generated identifier in the README. I'd like to use the new PhraseGenerator but I am not sure if the phrases can be longer than 22 chars (that's my restriction).

Implement request-response 'weave' pattern logging

Implement request-response 'weave' pattern logging which gives human readable way to follow correlated request-response log statements and concurrent request-response interleaving.

Idea is borrowed from here : https://pablosichert.github.io/concurrency-logger/

──‣ ┈┈┈┈┈ GET┈ ┬┈│┈│┈┈┈│┈┈ /
──‣ ┈┈┈┈┈ GET┈ │┈│┈│┈┬┈│┈┈ /
──‣ ┈┈┈┈┈ GET┈ │┈│┈│┈│┈│┈┬ /
200 ┈11ms GET┈ │┈┴┈│┈│┈│┈│ /
200 ┈┈4ms GET┈ │┈┈┈│┈│┈┴┈│ /
200 ┈┈6ms GET┈ │┈┈┈┴┈│┈┈┈│ /
──‣ ┈┈┈┈┈ GET┈ │┈┬┈┈┈│┈┈┈│ /
──‣ ┈┈┈┈┈ GET┈ │┈│┈┬┈│┈┈┈│ /
200 ┈┈5ms GET┈ │┈│┈┴┈│┈┈┈│ /
──‣ ┈┈┈┈┈ GET┈ │┈│┈┬┈│┈┈┈│ /
200 ┈21ms GET┈ │┈│┈│┈│┈┈┈┴ /
200 ┈27ms GET┈ │┈┴┈│┈│┈┈┈┈ /
──‣ ┈┈┈┈┈ GET┈ │┈┬┈│┈│┈┈┈┈ /
──‣ ┈┈┈┈┈ GET┈ │┈│┈│┈│┈┬┈┈ /
200 ┈42ms GET┈ │┈│┈│┈┴┈│┈┈ /
200 ┈23ms GET┈ │┈│┈┴┈┈┈│┈┈ /
200 ┈46ms GET┈ ┴┈│┈┈┈┈┈│┈┈ /

One possible (?) way is to store in logging context current weave pattern and log it as a part of logline along with flow-id

{TRACE} [XNIO-3 task-4] [R595UgNfSHSq0vDzTZsoMw] [│┈│┈┴┈┈┈│┈┈] [org.zalando.logbook.Logbook] {"origin":"remote","type":"response"...

The referenced implementation uses coloring and multiline log statements which could be omitted for initial implementation.

Close traces on servlet exception

Right now traces are not closed in case the servlet encounters an exception. This is a problem when the container decides to reuse the thread.

Spring Boot Auto Configuration not usable in WebFlux project

Currently, when including org.zalando:tracer-spring-boot-starter into Spring 5 reactive applications Spring cannot start (NoClassDefFoundError: javax/servlet/Filter) because of TracerAutoConfiguration's hard dependency on javax.servlet.Filter.

Caused by: java.lang.IllegalStateException: Failed to introspect Class [org.zalando.tracer.spring.TracerAutoConfiguration] from ClassLoader [sun.misc.Launcher$AppClassLoader@18b4aac2]
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:659)
	at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:556)
	at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:541)
	at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:599)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:726)
        ....
Caused by: java.lang.NoClassDefFoundError: javax/servlet/Filter

Expected Behavior

The application should start, but disable servlet filtering. All other configurations should be preserved.

Actual Behavior

It fails.

Possible Fix

Extract TracerFilterAutoConfiguration into separate class and add @ConditionalOnWebApplication there.

Stacked traces should not be deactivated

Hey guys :)
More of a question then an actual issue...

I introduced Tracer in our projects and wanted to introduce transaction Id stacking (flow id stacking in Zalando speech ;) ). Unfortunately Tracer does not support this in the current version.

My Intention is to have multiple Traces of the same name running at the same time. Basically I get a call through HTTP with an existing trace. To document where things are going from now on I add a new one to the same name (now there are two active) to make tracing of this specific part of the overall transaction easier.

Is there an easier way of doing this?
Or is this a possible feature for Tracer?

Expand scope and purpose of the library

Detailed Description

This library will be restructured and have it's scope and purpose shifted and extended at the same time. The library will be extended to into a collection of OpenTracing related libraries.

Context

The move from custom implementation (0-x and 1.x) to a utility library on top of OpenTracing (2.x) could already be seen as the first step in that direction. #209 also discusses some aspects in this regard. Ultimately it can be stated that the Tracer library is being phased out in favor of OpenTracing which we embrace even further.

Possible Implementation

  1. Rename project to opentracing-toolbox
    • Rename repository
    • Move current modules into nested module opentracing-flowid
    • Rename exsting modules from tracer-* to opentracing-flowid-*
    • Rename packages from org.zalando.tracer to org.zalando.opentracing.flowid
    • Rename Tracer* classes to FlowId*
    • Rename spring boot properties namespace from tracer to flowid
    • Get rid of MDCSpanObserver and dependency to opentracing-api-extensions-tracer (see next step)
  2. Add opentracing-proxy module (internal project right now)
  3. Add opentracing-jdbc module (internal project right now)
  4. Add opentracing-toolbox-spring-addons (name tbd)
    • Collection of HandlerInterceptorSpanDecorator
    • Support for WebFluxSpanDecorator might be added later
    • No support for RestTemplateSpanDecorator or WebClientSpanDecorator as for now because Riptide: OpenTracing already provides a better alternative
  5. Add opentracing-toolbox-spring-boot-autoconfigure (name tbd)
    • Multiple AutoConfigurations
    • Decorate Tracer using opentracing-proxy
    • Instrument DataSources using opentracing-jdbc
    • Bind HandlerInterceptorSpanDecorator
    • Configuration properties

📣 All instrumentation modules in this library will be customizable but have their default configuration set match Zalando's version of the semantic conventions.

Your Environment

  • Version used: 2.x

mdcTracer fails with NoopTracer instance

Description

In case client application doesn't have properly configured tracer and uses NoopTracer instance it will fail during incoming http call with 500 error.

Expected Behavior

Incoming http call should pass FlowFilter and reach application business logic.

Actual Behavior

Following exception thrown:

java.lang.NoSuchMethodError: io.opentracing.ScopeManager.active()Lio/opentracing/Scope;
	at io.opentracing.contrib.api.tracer.APIExtensionsTracer.activeSpan(APIExtensionsTracer.java:65)
	at io.opentracing.util.GlobalTracer.activeSpan(GlobalTracer.java:209)
	at io.opentracing.contrib.api.tracer.APIExtensionsTracer.activeSpan(APIExtensionsTracer.java:63)
	at org.zalando.tracer.DefaultFlow.activeSpan(DefaultFlow.java:75)
	at org.zalando.tracer.DefaultFlow.readFrom(DefaultFlow.java:23)
	at org.zalando.tracer.servlet.FlowFilter.doFilter(FlowFilter.java:25)
	at org.zalando.tracer.servlet.HttpFilter.doFilter(HttpFilter.java:28)

Possible Fix

Steps to Reproduce

The problem resides in utilising APIExtensionsTracer which is incompatible with OpenTracing-api 0.33.0.

Can be exposed by following test:

package org.zalando.tracer;

import io.opentracing.contrib.api.tracer.APIExtensionsTracer;
import io.opentracing.noop.NoopTracerFactory;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

class DefaultFlowNoopTracerTest {
    private final APIExtensionsTracer tracer = new APIExtensionsTracer(NoopTracerFactory.create());
    private final Flow unit = Flow.create(tracer);

    @Test
    void shouldThrowNoActiveSpanFoundException() {
        assertThrows(IllegalStateException.class, unit::currentId);
    }
}

Context

Your Environment

  • Version used: 2.0.0-RC.2
  • Link to your project:

Settle on a name

Detailed Description

We should settle on one and only one name that is not overloaded already.

Context

Given we follow the path outlined in #204 then we are in a somewhat fuzzy spot in terms of naming:

  • This library is historically called Tracer because it was meant to target a very specific aspect of distributed system tracing.
    The name was used consistently:
    • tracer repositoriy
    • tracer-* modules and artifacts
    • org.zalando.tracer package
    • Tracer main API
    • TracerFilter
    • TracerHttpRequestInterceptor
    • TracerAutoConfiguration
    • tracer configuration namespace (Spring Boot)
  • OpenTracing has its own concept and overloaded term of a Tracer, hence the switch to **Flow*.
    The name is not used consistently right now:
    • tracer repositoriy 💥
    • tracer-* modules and artifacts 💥
    • org.zalando.tracer package 💥
    • Flow main API
    • FlowFilter
    • FlowHttpRequestInterceptor
    • TracerAutoConfiguration 💥
    • tracer configuration namespace (Spring Boot) 💥

Tracer not working in logger with Kotlin coroutine

I'm using the default spring configuration and if I do this:

GlobalScope.launch{ someOperationThatUsuallyLogsWithTracer() }

I don't see the tracer in the logs.

Maybe I'm missing something in the settings?

Not sure if this is a bug or a feature request. Please feel free to ask for details in order to reproduce it.

Javadoc warnings

Expected Behavior

Javadocs should be generated without warnings.

Actual Behavior

mvn javadoc:javadoc -D maven.javadoc.failOnWarnings produces:

2 warnings
[WARNING] Javadoc Warnings
[WARNING] /home/wschoenborn/Projects/tracer/tracer-core/src/main/java/org/zalando/tracer/Flow.java:29: warning: no description for @return
[WARNING] * @return
[WARNING] ^
[WARNING] /home/wschoenborn/Projects/tracer/tracer-core/src/main/java/org/zalando/tracer/Flow.java:30: warning: no description for @throws
[WARNING] * @throws IllegalStateException
[WARNING] ^

Possible Fix

  • Write proper javadoc
  • enable failOnWarnings in javadoc plugin configuration

Steps to Reproduce

See above

Context

Release a new version

Issue with org.zalando.stups:tokens library and tracer.async.enabled

If we use tracer together with zalando tokens library (https://github.com/zalando-stups/spring-boot-zalando-stups-tokens) and have tracer.async.enabled: true and _@EnableAsync_, we get the following WARN log message every time the tokens are refreshed (by default every 5 seconds):

2016-07-28 14:58:03,194 {WARN} [restartedMain] [] [org.zalando.stups.tokens.CompositeMetricsListener] X-Flow-ID has not been started
java.lang.IllegalStateException: X-Flow-ID has not been started
    at com.google.common.base.Preconditions.checkState(Preconditions.java:199) ~[guava-19.0.jar:?]
    at org.zalando.tracer.DefaultTracer.getAndCheckValue(DefaultTracer.java:105) ~[tracer-core-0.8.0.jar:?]
    at org.zalando.tracer.DefaultTracer.lambda$forEach$4(DefaultTracer.java:84) ~[tracer-core-0.8.0.jar:?]
    at java.util.Map.forEach(Map.java:630) ~[?:1.8.0_91]
    at org.zalando.tracer.DefaultTracer.forEach(DefaultTracer.java:83) ~[tracer-core-0.8.0.jar:?]
    at org.zalando.tracer.Tracer.snapshot(Tracer.java:132) ~[tracer-core-0.8.0.jar:?]
    at org.zalando.tracer.Tracer.preserve(Tracer.java:166) ~[tracer-core-0.8.0.jar:?]
    at org.zalando.tracer.spring.TracerTaskExecutor.execute(TracerTaskExecutor.java:38) ~[tracer-spring-boot-starter-0.8.0.jar:?]
    at org.springframework.core.task.support.TaskExecutorAdapter.submit(TaskExecutorAdapter.java:106) ~[spring-core-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.aop.interceptor.AsyncExecutionAspectSupport.doSubmit(AsyncExecutionAspectSupport.java:273) ~[spring-aop-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.aop.interceptor.AsyncExecutionInterceptor.invoke(AsyncExecutionInterceptor.java:130) ~[spring-aop-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at com.sun.proxy.$Proxy85.submitToTimer(Unknown Source) ~[?:?]
    at org.zalando.stups.tokens.CompositeMetricsListener.submitToTimer(CompositeMetricsListener.java:23) [spring-boot-zalando-stups-tokens-0.9.11.jar:?]
    at org.zalando.stups.tokens.AccessTokenRefresher.createToken(AccessTokenRefresher.java:181) [tokens-0.9.9.jar:?]
    at org.zalando.stups.tokens.AccessTokenRefresher.run(AccessTokenRefresher.java:137) [tokens-0.9.9.jar:?]
    at org.zalando.stups.tokens.AccessTokenRefresher.start(AccessTokenRefresher.java:92) [tokens-0.9.9.jar:?]
    at org.zalando.stups.tokens.AccessTokensBuilder.start(AccessTokensBuilder.java:279) [tokens-0.9.9.jar:?]
    at org.zalando.stups.tokens.AccessTokensBean.start(AccessTokensBean.java:174) [spring-boot-zalando-stups-tokens-0.9.11.jar:?]
    at org.zalando.stups.tokens.config.AccessTokensBeanAutoConfiguration.accessTokensBean(AccessTokensBeanAutoConfiguration.java:66) [spring-boot-zalando-stups-tokens-0.9.11.jar:?]
    at org.zalando.stups.tokens.config.AccessTokensBeanAutoConfiguration$$EnhancerBySpringCGLIB$$e2ed77b5.CGLIB$accessTokensBean$0(<generated>) [spring-boot-zalando-stups-tokens-0.9.11.jar:?]
    at org.zalando.stups.tokens.config.AccessTokensBeanAutoConfiguration$$EnhancerBySpringCGLIB$$e2ed77b5$$FastClassBySpringCGLIB$$ff80ee9.invoke(<generated>) [spring-boot-zalando-stups-tokens-0.9.11.jar:?]
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) [spring-core-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356) [spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.zalando.stups.tokens.config.AccessTokensBeanAutoConfiguration$$EnhancerBySpringCGLIB$$e2ed77b5.accessTokensBean(<generated>) [spring-boot-zalando-stups-tokens-0.9.11.jar:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_91]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_91]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_91]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:464) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1046) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) [spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) [spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) [spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:760) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:360) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:306) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at de.zalando.atlas.catalog.api.CatalogApiApplication.main(CatalogApiApplication.java:19) [classes/:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_91]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_91]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_91]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.3.6.RELEASE.jar:1.3.6.RELEASE]

This seems to be because the code here assumes Tracer was already started: TracerTaskExecutor.java#L38

A workaround for this at the moment is to disable the MetricsListenerAutoConfiguration:

@EnableAutoConfiguration(exclude = {MetricsListenerAutoConfiguration.class})

Set up project modules

  • trace-core
  • trace-slf4j
  • trace-spring (maybe this can be done in a more generic way?)
  • trace-servlet
  • trace-cxf (maybe this can be done in a more generic way?)
  • trace-httpcomponents (as an alternative to spring + cxf)

Trace Provisioning

A common use case for stacked traces is to process a batch (outer trace) and start a specific trace per item being processed (inner trace). For event processing we keep a reference to the original trace id, so we use that as a seed. Currently we need to do this like this:

for (final Event event : batch.getEvents()) {
    tracer.start(withFlowIdOf(event));
    try {
        consumer.consume(event);
    } finally {
        tracer.stop();
    }
}

private Function<String, String> withFlowIdOf(final Event event) {
    return $ -> event.getMetadata().getFlowId();
}

I would be nice if Event could annotate a special method like this:

class Event {

    @ProvidesTrace("X-Flow-ID")
    public String getFlowId() {
        return getMetadata().getFlowId();
    }

}

for (final Event event : batch.getEvents()) {
    tracer.start(event);
    try {
        consumer.consume(event);
    } finally {
        tracer.stop();
    }
}

Alternatively there could be a special interface, but that would require that a) a class can only provide one and b) that every class needs to implement two methods, on for the name and one for the value.

Examples of how to tie to specifc vendor opentracing tracer.

There is no examples of how to use it:

  1. sample examples of how to use it in spring example app
  2. how to tie to vendor like lightstep.. or jaeger or any of those?

Detailed Description

Context

Possible Implementation

Your Environment

  • Version used:
  • Link to your project:

spring-boot-starter fails

When I try to run an application with tracer-spring-boot-starter version 0.6.0 with the configuration in application.yaml

tracer: aspect.enabled: true async.enabled: true filter.enabled: true logging: enabled: false category: org.zalando.tracer.Tracer mdc.enabled: true scheduling.enabled: true traces: X-Trace-ID: uuid X-Flow-ID: X-FLOW-ID

Then I got the following error. Can you please shed some light on this ?

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tracerFilter' defined in class path resource [org/zalando/tracer/spring/TracerAutoConfiguration.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.zalando.tracer.Tracer]: Error creating bean with name 'tracer' defined in class path resource [org/zalando/tracer/spring/TracerAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.zalando.tracer.Tracer]: Factory method 'tracer' threw exception; nested exception is java.lang.UnsupportedOperationException; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tracer' defined in class path resource [org/zalando/tracer/spring/TracerAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.zalando.tracer.Tracer]: Factory method 'tracer' threw exception; nested exception is java.lang.UnsupportedOperationException at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:464) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.boot.context.embedded.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:233) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:214) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:90) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:78) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getServletContextInitializerBeans(EmbeddedWebApplicationContext.java:237) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.selfInitialize(EmbeddedWebApplicationContext.java:224) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.access$000(EmbeddedWebApplicationContext.java:85) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext$1.onStartup(EmbeddedWebApplicationContext.java:209) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.springframework.boot.context.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:55) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5240) ~[tomcat-embed-core-8.0.33.jar:8.0.33] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147) ~[tomcat-embed-core-8.0.33.jar:8.0.33] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408) ~[tomcat-embed-core-8.0.33.jar:8.0.33] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398) ~[tomcat-embed-core-8.0.33.jar:8.0.33] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_45] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_45] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_45] at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_45] Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tracer' defined in class path resource [org/zalando/tracer/spring/TracerAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.zalando.tracer.Tracer]: Factory method 'tracer' threw exception; nested exception is java.lang.UnsupportedOperationException at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] ... 26 common frames omitted Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.zalando.tracer.Tracer]: Factory method 'tracer' threw exception; nested exception is java.lang.UnsupportedOperationException at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] ... 39 common frames omitted Caused by: java.lang.UnsupportedOperationException: null at org.zalando.tracer.spring.DefaultGeneratorResolver$$Lambda$46/780090089.get(Unknown Source) ~[na:na] at java.util.Optional.orElseThrow(Optional.java:290) ~[na:1.8.0_45] at org.zalando.tracer.spring.DefaultGeneratorResolver.resolve(DefaultGeneratorResolver.java:44) ~[tracer-spring-boot-starter-0.6.0.jar:na] at org.zalando.tracer.spring.TracerAutoConfiguration$$Lambda$44/692711475.apply(Unknown Source) ~[na:na] at com.google.common.collect.Maps$7.transformEntry(Maps.java:1812) ~[guava-18.0.jar:na] at com.google.common.collect.Maps$10.getValue(Maps.java:1857) ~[guava-18.0.jar:na] at java.util.Map.forEach(Map.java:625) ~[na:1.8.0_45] at org.zalando.tracer.spring.TracerAutoConfiguration.tracer(TracerAutoConfiguration.java:115) ~[tracer-spring-boot-starter-0.6.0.jar:na] at org.zalando.tracer.spring.TracerAutoConfiguration$$EnhancerBySpringCGLIB$$551674a.CGLIB$tracer$1(<generated>) ~[tracer-spring-boot-starter-0.6.0.jar:na] at org.zalando.tracer.spring.TracerAutoConfiguration$$EnhancerBySpringCGLIB$$551674a$$FastClassBySpringCGLIB$$99280dc5.invoke(<generated>) ~[tracer-spring-boot-starter-0.6.0.jar:na] at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.zalando.tracer.spring.TracerAutoConfiguration$$EnhancerBySpringCGLIB$$551674a.tracer(<generated>) ~[tracer-spring-boot-starter-0.6.0.jar:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45] at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] ... 40 common frames omitted

Improve performance of Random128Generator

Instead of using random64 + string concat, maybe it would be faster to generate a random byte array of size 16 and transform it into a hex string.

Current performance:


Benchmark                               Mode  Cnt         Score         Error  Units
Random128GeneratorBenchmark.benchmark  thrpt   20   6220510.086 ±  706340.069  ops/s
Random64GeneratorBenchmark.benchmark   thrpt   20  17923599.807 ± 1393506.401  ops/s

Two HttpFilter in tracer and logbook

You use two interfaces in your tracer and logbook module which do the same

  • org.zalando.logbook.servlet.HttpFilter
  • org.zalando.tracer.servlet.HttpFilter

Detailed Description

org.zalando.logbook.servlet.HttpFilter

interface HttpFilter extends Filter {

    @Override
    default void init(final FilterConfig filterConfig) {
        // no initialization needed by default
    }

    @Override
    default void doFilter(final ServletRequest request, final ServletResponse response,
            final FilterChain chain) throws ServletException, IOException {

        if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
            throw new IllegalArgumentException(getClass().getSimpleName() + " only supports HTTP");
        }

        final HttpServletRequest httpRequest = (HttpServletRequest) request;
        final HttpServletResponse httpResponse = (HttpServletResponse) response;

        doFilter(httpRequest, httpResponse, chain);
    }

    void doFilter(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse,
            final FilterChain chain) throws ServletException, IOException;

    @Override
    default void destroy() {
        // no deconstruction needed by default
    }
}

org.zalando.tracer.servlet.HttpFilter

interface HttpFilter extends Filter {

    @Override
    default void init(final FilterConfig filterConfig) {
        // no initialization needed by default
    }

    @Override
    default void doFilter(final ServletRequest request, final ServletResponse response,
            final FilterChain chain) throws ServletException, IOException {

        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            final HttpServletRequest httpRequest = (HttpServletRequest) request;
            final HttpServletResponse httpResponse = (HttpServletResponse) response;

            doFilter(httpRequest, httpResponse, chain);
        } else {
            throw new IllegalArgumentException(getClass().getSimpleName() + " only supports HTTP");
        }
    }
    
    void doFilter(final HttpServletRequest request, final HttpServletResponse response,
                final FilterChain chain) throws ServletException, IOException;
    
    @Override
    default void destroy() {
        // no deconstruction needed by default
    }
}

Context

Do you intend to somehow solve this or don't you want to have a common library shared across your modules?

Possible Implementation

Shared library?

Your Environment

We developed something very similiar to your tracer module and think about switching to your module. I came across this issue while I compared it to our module and if it would fit.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.