Giter Club home page Giter Club logo

opencensus-php's Introduction

Warning

OpenCensus and OpenTracing have merged to form OpenTelemetry, which serves as the next major version of OpenCensus and OpenTracing.

OpenTelemetry has now reached feature parity with OpenCensus, with tracing and metrics SDKs available in .NET, Golang, Java, NodeJS, and Python. All OpenCensus Github repositories, except census-instrumentation/opencensus-python, will be archived on July 31st, 2023. We encourage users to migrate to OpenTelemetry by this date.

To help you gradually migrate your instrumentation to OpenTelemetry, bridges are available in Java, Go, Python, and JS. Read the full blog post to learn more.

OpenCensus for PHP - A stats collection and distributed tracing framework

Census for PHP. Census provides a framework to measure a server's resource usage and collect performance stats. This repository contains PHP related utilities and supporting software needed by Census.

CircleCI Packagist PHP-Version

Installation & basic usage

  1. Install the opencensus/opencensus package using composer:

    $ composer require opencensus/opencensus:~0.2

    IMPORTANT: Please ensure your version is >= 0.2.0. There is a potential security vulnerability in < 0.2.0.

  2. [Optional]: Install the opencensus extension from PECL:

    $ pecl install opencensus-alpha

    Enable the extension in your php.ini:

    extension=opencensus.so
  3. Initialize a tracer for your application:

    use OpenCensus\Trace\Tracer;
    use OpenCensus\Trace\Exporter\EchoExporter;
    
    Tracer::start(new EchoExporter());

Usage

To add tracing to a block of code, you can use the closure/callable form or explicitly open and close spans yourself.

Closure/Callable (preferred)

$pi = Tracer::inSpan(['name' => 'expensive-operation'], function() {
    // some expensive operation
    return calculatePi(1000);
});

$pi = Tracer::inSpan(['name' => 'expensive-operation'], 'calculatePi', [1000]);

Explicit Span Management

// Creates a detached span
$span = Tracer::startSpan(['name' => 'expensive-operation']);

// Opens a scope that attaches the span to the current context
$scope = Tracer::withSpan($span);
try {
    $pi = calculatePi(1000);
} finally {
    // Closes the scope (ends the span)
    $scope->close();
}

Customization

Samplers

You can specify different samplers when initializing a tracer. The default sampler is the AlwaysSampleSampler which will attempt to trace all requests.

The provided samplers are:

Class Description
NeverSampleSampler Never trace any requests
AlwaysSampleSampler Trace all requests
MultiSampler Check multiple samplers
QpsSampler Trace X requests per second. Requires a PSR-6 cache implementation
ProbabilitySampler Trace X percent of requests.

If you would like to provide your own sampler, create a class that implements SamplerInterface.

Exporters

You can choose different exporters to send the collected traces to.

The provided exporters are:

Class Description Dependency
EchoExporter Output the collected spans to stdout
FileExporter Output JSON encoded spans to a file
JaegerExporter Report traces to Jaeger server via Thrift over UDP opencensus/opencensus-exporter-jaeger
LoggerExporter Exporter JSON encoded spans to a PSR-3 logger
NullExporter No-op
OneLineEchoExporter Output the collected spans to stdout with one-line
StackdriverExporter Report traces to Google Cloud Stackdriver Trace opencensus/opencensus-exporter-stackdriver
ZipkinExporter Report collected spans to a Zipkin server opencensus/opencensus-exporter-zipkin

If you would like to provide your own reporter, create a class that implements ExporterInterface.

Versioning

Packagist

This library follows Semantic Versioning.

Please note it is currently under active development. Any release versioned 0.x.y is subject to backwards incompatible changes at any time.

GA: Libraries defined at a GA quality level are stable, and will not introduce backwards-incompatible changes in any minor or patch releases. We will address issues and requests with the highest priority.

Beta: Libraries defined at a Beta quality level are expected to be mostly stable and we're working towards their release candidate. We will address issues and requests with a higher priority.

Alpha: Libraries defined at an Alpha quality level are still a work-in-progress and are more likely to get backwards-incompatible updates.

Current Status: Alpha

Contributing

Contributions to this library are always welcome and highly encouraged.

See CONTRIBUTING for more information on how to get started.

Releasing

See RELEASING for more information on releasing new versions.

License

Apache 2.0 - See LICENSE for more information.

Disclaimer

This is not an official Google product.

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

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?

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.

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 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();
    }
}

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

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 code style tests

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

Reimplement span kind

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

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] 

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!

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!

Build code documentation

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

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()) {

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.
}

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.

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.

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.

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.

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

Add php_info() section

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

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).

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

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.

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 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.

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.