Coder Social home page Coder Social logo

census-instrumentation / opencensus-php Goto Github PK

View Code? Open in Web Editor NEW
203.0 203.0 85.0 1.8 MB

A stats collection and distributed tracing framework

License: Apache License 2.0

M4 0.07% JavaScript 0.06% PHP 76.43% Shell 1.48% C 14.55% Dockerfile 0.15% Makefile 0.16% Go 7.11%

opencensus-php's People

Contributors

aabmass avatar albertojgomez avatar basvanbeek avatar bpot avatar bshaffer avatar castaneai avatar chingor13 avatar draffensperger avatar ericnorris avatar hectorj avatar jcchavezs avatar klibbbs avatar mrmage avatar stantheman 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

opencensus-php's Issues

Build code documentation

  • Find a documentation generator
  • Automatically build and publish documentation from master to gh-pages branch

Span has epoch as the startTime with PHP built-in webserver and cli

Here is the repro:

composer require google/cloud-trace opencensus/opencensus
<?php

require_once __DIR__ . '/vendor/autoload.php';

use OpenCensus\Trace\Exporter\EchoExporter;
use OpenCensus\Trace\Tracer;

$exporter = new EchoExporter();
Tracer::start($exporter);

Tracer::inSpan(
    ['name' => 'slow_function'],
    function () {
        usleep(1);
    }
);

Run it with cli and built-in webserver. The inner span has 1970-01-01 00:00:00.000000 as the startTime.

Segfault when using extension for StackdriverExporter or Wordpress integration

The following results in a segfault: 11 on PHP 7.0, 7.1, and 7.2:

/** Set up tracing integration */
use OpenCensus\Trace\Tracer;
use OpenCensus\Trace\Exporter\StackdriverExporter;
use OpenCensus\Trace\Integrations\Wordpress;

Tracer::start(new StackdriverExporter());
Wordpress::load();

Commenting either Tracer::start or Wordpress::load results in the same error, but if only the EchoExporter is used, the segfault does not happen.

This works just fine if I disable the opencensus.so extension.

Segfault during test suite

Not always... sometime
Will try to get a bactrace

OpenCensus Trace: Basic Class Method As Function Test [tests/basic_class_function.phpt]
OpenCensus Trace: Basic Function Test [tests/basic_function.phpt]
OpenCensus Trace: Basic Method Test [tests/basic_method.phpt]
OpenCensus Trace: Clear Traces [tests/clear_traces.phpt]
OpenCensus Trace: Nested spans [tests/nested_spans.phpt]
OpenCensus Trace: Basic Class Static Method [tests/static_method_test.phpt]
OpenCensus Trace: Trace Context [tests/trace_context.phpt]

All with Termsig=11

Attempted to call an undefined method named "context" of class "OpenCensus\Trace\Tracer".

Hi!

Trying to use the Guzzle middleware always throws an exception :

Symfony\Component\Debug\Exception\UndefinedMethodException:
Attempted to call an undefined method named "context" of class "OpenCensus\Trace\Tracer".

  at vendor/opencensus/opencensus/src/Trace/Integrations/Guzzle/Middleware.php:72
  at OpenCensus\Trace\Integrations\Guzzle\Middleware->OpenCensus\Trace\Integrations\Guzzle\{closure}(object(Request), array('synchronous' => true, 'base_uri' => object(Uri), 'handler' => object(HandlerStack), 'connect_timeout' => 30, 'read_timeout' => 30, 'timeout' => 30, 'allow_redirects' => array('max' => 5, 'protocols' => array('http', 'https'), 'strict' => false, 'referer' => false, 'track_redirects' => false), 'http_errors' => true, 'decode_content' => true, 'verify' => true, 'cookies' => false))
     (vendor/guzzlehttp/guzzle/src/HandlerStack.php:67)

It's this line that calls an undefined method :

if ($context = Tracer::context()) {

Add code style tests

We can use squizlabs/php_codesniffer and add tests to make sure we have consistent code style.

Split Read Only/Write Span APIs

Span should have write-only APIs expect SpanContext getContext(). This is important because we should not encourage users to pass data around function calls using Span.

foo() {
  span.addAttribute("MyValue", "XXX");
  bar();
}

void bar() {
  String my_string = span.getAttribute("MyValue");
} 

We should add a SpanData that is a read-only api which is the object that is passed to the exporters for example. Also this is consistent with all other languages.

If users want to propagate data around they should use the Context API.

Cannot set attributes on a detached span after the span is attached

Note: the following also applies to adding annotations, links, message events, etc. to spans.

Consider:

$span = Tracer::startSpan(['name' => 'root']);
$scope = Tracer::withSpan($span);
$span->addAttribute('foo', 'bar');
$scope->close();

This will work using the ContextTracer as the $span is a reference to the tracked span. This will not work for the extension as the $span is not a reference to the object being held in the extension's memory.

We could resolve this by delegating the addition of attributes to the TracerInterface implementation:

interface TracerInterface
{
    ...
    // option 1
    public function addAttribute(Span $span, $key, $value);

    // option 2, $options['span'] would be the span, otherwise assume the current span.
    public function addAttribute($key, $value, $options = []);
}

The previous example would look like:

$span = Tracer::startSpan(['name' => 'root']);
$scope = Tracer::withSpan($span);

// option 1
Tracer::addAttribute($span, 'foo', 'bar');

// option 2
Tracer::addAttribute('foo', 'bar', ['span' => $span]);

$scope->close();

Option 1 precludes you from being able to add attributes to the current span (common in the implicit span usage). Option 2 gets a bit hairy when applied to something like annotations or links where those models also have optional values.

Add php_info() section

The section should report the version, whether the extension is enabled or not, and any php.ini allowed configurations.

Fix dev dependency on google/cloud

When the trace v2 version is officially shipped to packagist, replace the dev dependency for google/cloud to google/cloud-trace version >= 0.4.x

Collect stacktrace for each span

We should be able to capture the stacktrace for each collected span.
Each reporter can choose to do something with that data.

ZipkinExporter: 400 Bad Request when there is no attributes

Hi!

I found a small problem with the ZipkinExporter for spans with no attributes : the report API call gives a 400 Bad Request.

According to my tests, it's because the empty attributes array is serialized as [], while a JSON object is expected by Zipkin ({}).

I'm submitting a PR right now to fix that.

Split the logic of "current" span/context into a separate class

I would suggest to decouple the logic of "current" Context/Span from the Tracer class, by having a separate Context class similar with io.grpc.Context

Here is a possible interface, stolen from Java, that will also work for async (it is essentially a map key->value):

class Context {

class Key<V> {
// Gets the value from the Context.current() context for this key.
V get();

// Get the value from the specified context for this key.
V get(Context c);
}

// Creates a new context with the given key value set.
Context withValue(Context.Key<V> k1, V v1);

// Attaches this context, thus enter a new scope within which this context is current().
// The previously current context is returned.
Context attach();

// Reverses an attach(), restoring the previous context and exiting the current scope.
void detach(Context toAttach);

// Returns the context associated with the current scope, will never return null.
static Context current();

// Creates a Context.Key with the given debug name.
static <T> Context.Key<T> key(String name);

// Returns empty context
static Context background();
}

The main advantages are:

  • Context can be reused in the future by other apis like "tags" etc.
  • As you can see the detach requires a toAttach context, this makes behavior deterministic:
void foo() {
  Context prev = Context.withValue(...).attach;
  try {
    // Imagine that bar changes the current context without cleaning before return.
    bar();
  } finally {
    // This makes sure that prev will be current after this execution.
    Context.current().detach(prev);
  }
  // here 100% sure prev is the current context.
}

Improve integration testing

Ideally, we should be able to run tests against sample applications running test code in a webserver. This will allow us to test things like framework integrations, response codes, and other edge cases that are hard to test with only unit tests.

  • Curl
  • Doctrine
  • Eloquent
  • Grpc
  • Guzzle
  • Laravel
  • Memcached
  • Mysql
  • PDO
  • Postgres
  • Symfony
  • Wordpress

Zipkin exporter observations

A couple of observations related to zipkin exporter:

  1. Since the reporter only uses one endpoint from the backend, zipkin instrumentations usually don't store host/port and uri but the full endpoint url instead endpointUrl="http://localhost:9411/api/v2/spans.
  2. In the exported format there is no kind attribute (link), is it possible it is being added as a tag and gets lost because of that?

If you consider these observations are valid I could help with them.

Add support for "detached" spans

Imagine this code in a framework:

class InterceptorFoo {
  // executed at the beginning
  void onReceive() {
    Tracer.start("xyz");
  }

  // executed to run the request
  void onRun(Handler h) {
    Tracer.addAnnotation("starting executing handler");
    h();
    Tracer.addAnnotation("finished executing handler");
  }

  // executed at the end of the request
  void onEnd() {
    Tracer.endSpan()
  } 
}

This code does not have any way to guarantee that you are appending to the right span or that you end the right span because the framework may also use opencensus and they may call:

void on_receive_framework_function() {
  Tracer.start("MyFrameworkSpan");
  try {
    interceptor.onReceive();
  } finally {
    Tracer.endSpan();
  }
}

We should support have a way to do something that is more secure here:

class InterceptorFoo {
  Span span;
  // executed at the beginning
  void onReceive() {
    span = Tracer.startSpan("xyz");
  }

  // executed to run the request
  void onRun(Handler h) {
    span.addAnnotation("starting executing handler");
    // make span current
    Scope s = Tracer.withSpan(span);
    try {
      h();
    } finally {
      // Just detach the span from the context.
      s.close();
    }
    span.addAnnotation("finished executing handler");
  }

  // executed at the end of the request
  void onEnd() {
    span.end()
  } 
}

where Scope just attaches/detaches the span from the context

interface Scope {
  // Must be called in a try statement in the finally part
  void close();
}

With the same interface, now that we have startSpan returning a detached span we can have a "inScope" (not necessary this name):

void foo() {
    // starts a span and attaches it to the context
    Scope s = Tracer.inScope("myScopedSpan");
    try {
      doSomethinInSpan();
    } finally {
      // detaches the span from the context and also calls span#end().
      s.close();
    }
}

Add a getContext -> SpanContext in the Span

the SpanContext contains the ids that uniquely identify a Span (trace_id, span_id) and the propagated trace options.

Every Span class should have it's own SpanContext:

class Span {
  SpanContext getContext() {
    return my_own_context;
  }
}

We should also remove the context() from the Tracer because that was the incoming SpanContext but when we make a call to a different user we should not use that context we actually should use the SpanContext of the current Span.

=======================   // Client in JS
    Sent.RequestSpanA       // SpanA
=======================
           | here we should have the SpanContext of the "SpanA" that way "SpanB" is a child of "SpanA"
=======================   // Service in PHP
    Recv.RequestSpanB       // SpanB
=======================
    Sent.RequestSpanC       // SpanC
=======================
           | here we should have the SpanContext of the "SpanC" that way "SpanD" is a child of "SpanC"
=======================  // DB in Java
    Recv.RequestSpanA       // SpanD
=======================

If I would have to write an instrumentation using the current API in PHP when I make the call to the DB I would probably propagate the RequestTracer.context(); which actually is the SpanContext of the "SpanA".

Undefined class constant 'HTTP_REDIRECTED_URL' error

If the request returns a redirect status code then RequestHandler.php tries to add a HTTP_REDIRECTED_URL attribute to the span but fails because HTTP_REDIRECTED_URL is only defined in StackdriverExporter.php.

I'm not sure what the correct fix is here. We could define the value in RequestHandler.php but it seems like this is functionality that should live in the stack driver exporter.

Allow Tracer usage in code which may or may not have an active tracer

The span methods on OpenCensus\Trace\Tracer assume that a trace has already been started and will throw an error (e.g. Call to a member function tracer() on null) if they are called without an active trace instance.

We got bit by this because we have multiple entry points in our codebase some of which started a trace and some of which didn't. It seems like it would be useful to either make all of the calls on Tracer no-ops if there isn't an instance or provide a Tracer::active() method which can be used as a guard around calls to the other Tracer methods.

I'm happy to send a PR for whichever path is seems best.

FileExporter report fail to serialize spans

As OpenCensus\Trace\Span does not implements JsonSerializable, calling json_encode on $tracer->spans() will produce empty JSON objects.

I see two options here:

  1. convert OpenCensus\Trace\Span into Google\Cloud\Trace\Span following StackdriverExporter approach;
  2. or force OpenCensus\Trace\Span implement JsonSerializable

For testing propose I already implemented the first option here.

Any thoughts on this issue?

Thanks!

Async data export

Most exporters currently execute at the end of the request while blocking the end of the request. The StackdriverExporter can use an experimental mechanism provided by the google/cloud-core package that uses shared memory for offloading the API call to a separate process.

We can create an AsyncExporter (for any async method) that accepts any other ExporterInterface and reports using that exporter asynchronously. This should make it so that each exporter doesn't have to manage async itself.

Add Jaeger UDP Exporter

To help with performance (since PHP isn't multithreaded and requires a batch runner), it would be great for the exporter to take advantage of some of these tracing backends' UDP endpoints. I believe Jaeger has one. This would save users who are using these exporters to have much better performance out of the box!

Reimplement span kind

Stackdriver Trace and Zipkin both support the kind of span (client, server, or unknown)

Capture same_process_as_parent_span

We should be able to detect sane defaults for this rather than not setting it. In our case, generally the root span will be set to false, and every other span (that PHP sees) will be set to true (single threaded web requests).

Undefined offset: 0 in StackdriverExporter

When the reporter does not need to post the spans i get the following error:

<b>Notice</b>:  Undefined offset: 0 in <b>/data/JIP-Accounts-API/vendor/opencensus/opencensus/src/Trace/Exporter/StackdriverExporter.php</b> on line <b>238</b><br />

But the error is gone when i for example update the probability sampler to 1.

My setup

$reporter = new StackdriverExporter([
    "async"        => TRUE,
    "clientConfig" => $this->config,
]);

Tracer::start(
    $reporter,
    [
        "sampler" => new ProbabilitySampler(LOCAL ? 0 : 0.1), // sample 10% of requests
        "headers" => $this->headers,
    ]
);

Is this a bug in this lib or am i doing something wrong?

Failed test on 32-bit

TEST 17/32 [tests/manual_spans_default_options.phpt]
========DIFF========
007+             [spanId:protected] => -1034353423
007-             [spanId:protected] => %d
020+             [spanId:protected] => -851458494
021+             [parentSpanId:protected] => -1034353423
020-             [spanId:protected] => %d
021-             [parentSpanId:protected] => %d
========DONE========
FAIL OpenCensus Trace: Customize the trace span options for a function [tests/manual_spans_default_options.phpt] 

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.