/* SPDX-License-Identifier: LGPL-2.1-or-later */

#ifndef _OTEL_SCOPE_H_
#define _OTEL_SCOPE_H_

#define FLT_OTEL_SCOPE_SPAN_FINISH_REQ       "*req*"
#define FLT_OTEL_SCOPE_SPAN_FINISH_RES       "*res*"
#define FLT_OTEL_SCOPE_SPAN_FINISH_ALL       "*"

#define FLT_OTEL_RT_CTX(p)                   ((struct flt_otel_runtime_context *)(p))

#define FLT_OTEL_DBG_SCOPE_SPAN(h,p)                                \
	OTELC_DBG(DEBUG, h "%p:{ '%s' %zu %u %hhu %p %p %p }", (p), \
	          FLT_OTEL_STR_HDR_ARGS(p, id), (p)->smp_opt_dir,   \
	          (p)->flag_finish, (p)->span, (p)->ref_span, (p)->ref_ctx)

#define FLT_OTEL_DBG_SCOPE_CONTEXT(h,p)                           \
	OTELC_DBG(DEBUG, h "%p:{ '%s' %zu %u %hhu %p }", (p),     \
	          FLT_OTEL_STR_HDR_ARGS(p, id), (p)->smp_opt_dir, \
	          (p)->flag_finish, (p)->context)

#define FLT_OTEL_DBG_SCOPE_DATA_EVENT(h,p)                    \
	OTELC_DBG(DEBUG, h "%p:{ '%s' %p %zu %zu %s }", &(p), \
	          (p).name, (p).attr, (p).cnt, (p).size,      \
	          flt_otel_list_dump(&((p).list)))

#define FLT_OTEL_DBG_SCOPE_DATA_STATUS(h,p) \
	OTELC_DBG(DEBUG, h "%p:{ %d '%s' }", (p), (p)->code, OTELC_STR_ARG((p)->description))

#define FLT_OTEL_DBG_SCOPE_DATA_KV_FMT       "%p:{ %p %zu %zu }"
#define FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS(p)   &(p), (p).attr, (p).cnt, (p).size
#define FLT_OTEL_DBG_SCOPE_DATA(h,p)                                                                                   \
	OTELC_DBG(DEBUG, h "%p:{ " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " %s %s }", (p), \
	          FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->baggage), FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->attributes),    \
	          flt_otel_list_dump(&((p)->events)), flt_otel_list_dump(&((p)->links)))

#define FLT_OTEL_DBG_RUNTIME_CONTEXT(h,p)                                                     \
	OTELC_DBG(DEBUG, h "%p:{ %p %p '%s' %hhu %hhu 0x%02hhx 0x%08x %u %d %s %s }", (p),    \
	          (p)->stream, (p)->filter, (p)->uuid, (p)->flag_harderr, (p)->flag_disabled, \
	          (p)->logging, (p)->analyzers, (p)->idle_timeout, (p)->idle_exp,             \
	          flt_otel_list_dump(&((p)->spans)), flt_otel_list_dump(&((p)->contexts)))

/* Anonymous struct containing a const string pointer and its length. */
#define FLT_OTEL_CONST_STR_HDR(p)    \
	struct {                     \
		const char *p;       \
		size_t      p##_len; \
	}


/* Growable key-value array for span attributes or baggage. */
struct flt_otel_scope_data_kv {
	struct otelc_kv *attr; /* Key-value array for storing attributes. */
	size_t           cnt;  /* Number of currently used array elements. */
	size_t           size; /* Total number of array elements. */
};

/* Named event with its own key-value attribute array. */
struct flt_otel_scope_data_event {
	char            *name; /* Event name, not used for other data types. */
	struct otelc_kv *attr; /* Key-value array for storing attributes. */
	size_t           cnt;  /* Number of currently used array elements. */
	size_t           size; /* Total number of array elements. */
	struct list      list; /* Used to chain this structure. */
};

/* Span link referencing another span or span context. */
struct flt_otel_scope_data_link {
	struct otelc_span         *span;    /* Linked span, or NULL. */
	struct otelc_span_context *context; /* Linked span context, or NULL. */
	struct list                list;    /* Used to chain this structure. */
};

/* Span status code and description. */
struct flt_otel_scope_data_status {
	int   code;        /* OTELC_SPAN_STATUS_* value. */
	char *description; /* Span status description string. */
};

/* Aggregated runtime data collected during scope execution. */
struct flt_otel_scope_data {
	struct flt_otel_scope_data_kv     baggage;    /* Defined scope baggage. */
	struct flt_otel_scope_data_kv     attributes; /* Defined scope attributes. */
	struct list                       events;     /* Defined scope events. */
	struct list                       links;      /* Defined scope links. */
	struct flt_otel_scope_data_status status;     /* Defined scope status. */
};

/* flt_otel_runtime_context->spans */
struct flt_otel_scope_span {
	FLT_OTEL_CONST_STR_HDR(id);             /* The span operation name/len. */
	uint                       smp_opt_dir; /* SMP_OPT_DIR_RE(Q|S) */
	bool                       flag_finish; /* Whether the span is marked for completion. */
	struct otelc_span         *span;        /* The current span. */
	struct otelc_span         *ref_span;    /* Span to which the current span refers. */
	struct otelc_span_context *ref_ctx;     /* Span context to which the current span refers. */
	struct list                list;        /* Used to chain this structure. */
};

/* flt_otel_runtime_context->contexts */
struct flt_otel_scope_context {
	FLT_OTEL_CONST_STR_HDR(id);             /* The span context name/len. */
	uint                       smp_opt_dir; /* SMP_OPT_DIR_RE(Q|S) */
	bool                       flag_finish; /* Whether the span context is marked for completion. */
	struct otelc_span_context *context;     /* The current span context. */
	struct list                list;        /* Used to chain this structure. */
};

/* The runtime filter context attached to a stream. */
struct flt_otel_runtime_context {
	struct stream *stream;        /* The stream to which the filter is attached. */
	struct filter *filter;        /* The OpenTelemetry filter. */
	char           uuid[40];      /* Randomly generated UUID. */
	bool           flag_harderr;  /* [0 1] */
	bool           flag_disabled; /* [0 1] */
	uint8_t        logging;       /* [0 1 3] */
	uint           analyzers;     /* Executed channel analyzers. */
	uint           idle_timeout;  /* Idle timeout interval in milliseconds (0 = off). */
	int            idle_exp;      /* Tick at which the next idle timeout fires. */
	struct list    spans;         /* The scope spans. */
	struct list    contexts;      /* The scope contexts. */
};


#ifndef DEBUG_OTEL
#  define flt_otel_scope_data_dump(...)   while (0)
#else
/* Dump scope data contents for debugging. */
void                             flt_otel_scope_data_dump(const struct flt_otel_scope_data *data);
#endif

/* Allocate and initialize a runtime context for a stream. */
struct flt_otel_runtime_context *flt_otel_runtime_context_init(struct stream *s, struct filter *f, char **err);

/* Free the runtime context attached to a filter. */
void                             flt_otel_runtime_context_free(struct filter *f);

/* Allocate and initialize a scope span in the runtime context. */
struct flt_otel_scope_span      *flt_otel_scope_span_init(struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len, const char *ref_id, size_t ref_id_len, uint dir, char **err);

/* Free a scope span and remove it from the runtime context. */
void                             flt_otel_scope_span_free(struct flt_otel_scope_span **ptr);

/* Allocate and initialize a scope context in the runtime context. */
struct flt_otel_scope_context   *flt_otel_scope_context_init(struct flt_otel_runtime_context *rt_ctx, struct otelc_tracer *tracer, const char *id, size_t id_len, const struct otelc_text_map *text_map, uint dir, char **err);

/* Free a scope context and remove it from the runtime context. */
void                             flt_otel_scope_context_free(struct flt_otel_scope_context **ptr);

/* Initialize scope data arrays and lists. */
void                             flt_otel_scope_data_init(struct flt_otel_scope_data *ptr);

/* Free all scope data contents. */
void                             flt_otel_scope_data_free(struct flt_otel_scope_data *ptr);

/* Mark a span for finishing by name in the runtime context. */
int                              flt_otel_scope_finish_mark(const struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len);

/* End all spans that have been marked for finishing. */
void                             flt_otel_scope_finish_marked(const struct flt_otel_runtime_context *rt_ctx, const struct timespec *ts_finish);

/* Free scope spans and contexts no longer needed by a channel. */
void                             flt_otel_scope_free_unused(struct flt_otel_runtime_context *rt_ctx, struct channel *chn);

#endif /* _OTEL_SCOPE_H_ */

/*
 * Local variables:
 *  c-indent-level: 8
 *  c-basic-offset: 8
 * End:
 *
 * vi: noexpandtab shiftwidth=8 tabstop=8
 */
