-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C89 API Proposal #1
Conversation
How do the tracer and span objects get destroyed? |
The spans and tracer need to be derived from the destructible interface. Not sure what I was doing here. Will fix. |
src/opentracing-c/tracer.h
Outdated
*/ | ||
int (*inject)(struct opentracing_tracer* tracer, | ||
opentracing_propagation_format format, | ||
void* carrier); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where's the extract function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another oversight. Thanks.
.clang-format
Outdated
Priority: 1 | ||
- Regex: '^"' | ||
Priority: 2 | ||
- Regex: '^"jaegertracingc/' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to change to opentracingc
.
README.md
Outdated
# OpenTracing API for C |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preserve original title. Make this subtext.
src/opentracing-c/tracer.h
Outdated
} opentracing_start_span_options; | ||
|
||
/** Tracer interface. */ | ||
typedef struct opentracing_tracer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to extend destructible.
/** Value type. */ | ||
opentracing_value_type type; | ||
/** Value storage. */ | ||
union { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid anonymous union.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
* span ID, baggage). | ||
* @extends opentracing_destructible | ||
*/ | ||
typedef struct opentracing_span_context { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to extend destructible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
src/opentracing-c/span.h
Outdated
struct opentracing_tracer; | ||
|
||
/** Span interface. */ | ||
typedef struct opentracing_span { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to extend destructible.
Could we include a dynamic loading interface as part of the C API? I think an app linking to the C-API but being able to dynamically load a C++ tracer with a C-C++ bridge would be a good scenario to support. |
Definitely. I'll work on that too unless you want to do it. Another eventual goal would be to implement a bridge on top of the C++ implementation for C libraries looking to adopt a C++ client without wrapping it themselves. |
src/opentracing-c/tracer.c
Outdated
(void) tracer; | ||
(void) operation_name; | ||
(void) options; | ||
null_span* span = (null_span*) malloc(sizeof(null_span)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the noop tracer even need to allocate memory? Couldn't it just return a pointer to a single instance of null_span?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case yes, and I can change it, as long as that wouldn't be the case for a real tracer.
I was tempted to make advertise this API as not allocating any heap memory, but that wouldn't be true for any instrumented process using a tracer. The only way around that is essentially capping the size of each object and reserving space for it in a stack buffer. See sockaddr_storage
details here for a similar idea with IPv4 and IPv6 addresses.
src/opentracing-c/tracer.c
Outdated
opentracing_span base; | ||
opentracing_span_context null_span_context; | ||
opentracing_tracer* null_tracer; | ||
} null_span; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really? I don't have a strong preference, but I find no-op hard to spell in code (is it NoOp
or Noop
?). Null has easy breaking and brings the null object pattern to mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be arguments for null if this API was considered in insolation; but given that all the other tracing APIs use noop, I think it's going to be confusing to have the C-API use a different naming scheme.
About the dynamic linking @rnburn, I've taken a look at the C++ version which requires a C++ TracerFactory object be loaded from a shared library. That can't be done in a pure C library. What equivalent would you suggest? |
Why not use your C inheritance model and return a pointer to some kind of tracer factory struct? typedef struct opentracing_tracer_factory {
opentracing_destructible base;
int make_tracer(struct opentracing_tracer_factorty* factory, const char* config, opentracing_tracer** tracer_out, char** error_message);
}; I used a factory instead of creating a tracer directly to handle the case where you might want to reconstruct a new tracer with a different configuration. |
That makes sense. Would you mind if I used a function instead? Like |
Yes, I think that would work. One advantage of the struct is that it could allow you to support having different functions to construct a tracer, but if there's only one I think a function pointer works fine. |
src/opentracing-c/span.h
Outdated
*/ | ||
opentracing_bool (*set_tag)(struct opentracing_span* span, | ||
const char* key, | ||
const opentracing_value* value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to be returning an error code for these functions? It doesn't seem like there's anything a user would want to do other than log, which a tracer implementation would be doing anyways (the Go API doesn't use error codes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I agree we can avoid burdening the user with these issues. If you don't think there is a case where a user needs to know that set_tag
etc. succeeded or OOM occurred, then I don't have a problem using void
as the return type.
src/opentracing-c/span.h
Outdated
* empty string. | ||
*/ | ||
const char* (*baggage_item)(const struct opentracing_span* span, | ||
const char* key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this return an allocated string that must be freed?
If not, what happens if a user gets a baggage item, then calls set_baggage_item to set a new value for the key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a fair point, but I guess it relies heavily on the implementation of this map (which I have left undefined). My gut tells me this should be a case of invalidated pointer, similar to getting an iterator from std::vector
, pushing an item to the back of the vector, and attempting to dereference the initial iterator. There are no guarantees we won't need to reallocate the underlying buffer with that push, so all references are invalidated. If you are OK with that, I will add it to the docs.
I guess so. I can change it to a void pointer, but I realized while writing this that the magic number would only work with ABI-compatible types. So casting from an old type definition to a new type definition would be a problem even within the same vendor (not sure how this would happen, maybe with dynamic loading). So I think I should just make a method like |
Rethinking this yet again... A void pointer actually means nothing if we can't cast it to "check" for properties. I'm back to the magic number as the simplest solution. Consider this problem:
|
An interesting C++ question related to implementing RTTI: https://stackoverflow.com/q/7525942/1930331. |
This is the way I would see it working: typedef struct dummy_type {
} dummy;
typedef struct base_type {
const void* type_signature;
} base_type;
typedef struct derived_type_a {
base_type base;
int a;
} derived_type_a;
static dummy type_a_id;
static int check_type_a(const base_type* base)
{
return base->type_signature == &type_a_id;
}
static dummy type_b_id;
typedef struct derived_type_b {
base_type base;
double b;
} derived_type_b;
static int check_type_b(const base_type* base)
{
return base->type_signature == &type_b_id;
}
int main()
{
derived_type_a a;
((base_type*) &a)->type_signature = &type_a_id;
derived_type_b b;
((base_type*) &b)->type_signature = &type_b_id;
base_type* base = &b;
check_type_a(b);
return 0;
} |
OK so that is exactly what I saw in the StackOverflow question. I think it works here, seeing as we have no other RTTI. The only thing I saw there was that the address is unique as long as the module is loaded. Not 100% sure how that could affect this. |
@rnburn are you okay the new proposal for a |
src/opentracing-c/tracer.h
Outdated
opentracing_propagation_format format, | ||
void* carrier, | ||
opentracing_span_context** span_context) OPENTRACINGC_NONNULL(); | ||
} opentracing_tracer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a close function for the tracer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well the question is whether or not destroy
is implicitly the same as close
. I guess not. Good idea.
So not something that would affect the API at all, but would you consider following a directory structure where the installed headers are separated from the src directory and non-installed headers. IMO it makes it easer to browse the API since you only need to look at the include directory. This is the directory structure used by all of the boost libraries (see for example boost/filesystem). |
Hey @heyleke -- any thoughts on the C API? It allows support for tracers completely in C and doesn't require C11, which is what I think you were originally interested in. |
I get that. OTOH I find the use of an include directory a nuisance. There are projects with both styles. |
@rnburn are you ready to accept? I know it would be better if others reviewed, but just your personal review? |
@isaachier - the part I don't like is renaming the noop tracer to the null tracer, as noop is consistently used across all the other OT APIs. But if there's others that buy into moving towards null instead of noop for the APIs, then I'd be ok with it. |
If that is the only thing, I'm fine with changing it. |
Done |
src/opentracing-c/tracer.h
Outdated
struct opentracing_tracer* tracer, | ||
opentracing_propagation_format format, | ||
void* carrier, | ||
const opentracing_span_context* span_context) OPENTRACINGC_NONNULL_ALL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was some discussion on opentracing/opentracing-go#127 on getting rid of the format parameter, which is why it's not in the C++ API. Does it make sense to have it for the C API?
This looks good to me. The only question I had was whether we should be using the propagation_format argument since the consensus from opentracing/opentracing-go#127 seemed to be that we should drop them. But I'll let you decide whether that's a good idea for OT-C or not. |
Thanks for approving. I see what you are saying. Maybe I can just use an opaque carrier instead of a format |
@rnburn I updated the methods to account for all cases of the enum. Please let me know what you think when you have a chance. |
Meant to be compatible with C++, so pure ANSI C.