census-instrumentation / opencensus-php Goto Github PK
View Code? Open in Web Editor NEWA stats collection and distributed tracing framework
License: Apache License 2.0
A stats collection and distributed tracing framework
License: Apache License 2.0
I was getting
PHP Warning: func_get_arg(): Argument 1 not passed to function in /app/vendor/opencensus/opencensus/src/Trace/Integrations/Wordpress.php on line 40
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
.
They point to https://opencensus.io/opencensus-php/api/OpenCensus/Trace/Exporter/EchoExporter.html, but there are no docs present!
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.
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
https://github.com/census-instrumentation/opencensus-proto/blob/master/trace/trace.proto
The extension and PHP models returned should match these structures.
API format: http://zipkin.io/zipkin-api/#/default/post_spans
From logs:
http://windows.php.net/downloads/pecl/releases/opencensus/0.0.1/logs/
C:\php-snap-build\php-src\php71\x86\php-src\configure.js(5384, 1) Microsoft JScript runtime error: 'PHP_OPENCENSUS_TRACE' is undefined
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 :
We can use squizlabs/php_codesniffer
and add tests to make sure we have consistent code style.
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.
See census-instrumentation/opencensus-java#550 for encoding format.
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.
The section should report the version, whether the extension is enabled or not, and any php.ini
allowed configurations.
Now the exception is thrown away at
Maybe we can get the message from the exception and use error_log
to notify the failure to users.
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
We should be able to capture the stacktrace for each collected span.
Each reporter can choose to do something with that data.
See here a good post about this:
https://gist.github.com/chrisjacob/833223
grpc also does that:
https://github.com/grpc/grpc-java/tree/gh-pages
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.
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:
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.
}
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.
A couple of observations related to zipkin exporter:
endpointUrl="http://localhost:9411/api/v2/spans
.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.
Which make impossible to run test for PECL archive
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();
}
}
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".
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.
The only stacktrace is:
array_map
<path>/vendor/opencensus/opencensus/src/Trace/Tracer/ExtensionTracer.php:119
Seems like API documentation is missing
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.
As OpenCensus\Trace\Span
does not implements JsonSerializable
, calling json_encode
on $tracer->spans()
will produce empty JSON objects.
I see two options here:
OpenCensus\Trace\Span
into Google\Cloud\Trace\Span
following StackdriverExporter
approach;OpenCensus\Trace\Span
implement JsonSerializable
For testing propose I already implemented the first option here.
Any thoughts on this issue?
Thanks!
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.
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!
Stackdriver Trace and Zipkin both support the kind of span (client, server, or unknown)
http://opencensus.io/opencensus-php should have a landing page with helpful pages about how to install and integration frameworks and libraries.
The generated API docs should be in a subfolder like http://opencensus.io/opencensus-php/api/
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).
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?
FYI, I discover that both extensions are loaded, lot of strange issues appear
Pleae see https://github.com/nbs-system/snuffleupagus/issues/133
From trace.proto.
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]
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.