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

#ifndef _OTEL_CONF_H_
#define _OTEL_CONF_H_

/* Extract the OTel filter configuration from a filter instance. */
#define FLT_OTEL_CONF(f)              ((struct flt_otel_conf *)FLT_CONF(f))

/* Expand to a string pointer and its length for a named member. */
#define FLT_OTEL_STR_HDR_ARGS(p,m)    (p)->m, (p)->m##_len
/***
 * It should be noted that the macro FLT_OTEL_CONF_HDR_ARGS() does not have
 * all the parameters defined that would correspond to the format found in
 * the FLT_OTEL_CONF_HDR_FMT macro (first pointer is missing).
 *
 * This is because during the expansion of the OTELC_DBG_STRUCT() macro, an
 * incorrect conversion is performed and instead of the first correct code,
 * a second incorrect code is generated:
 *
 * do {
 *    if ((p) == NULL)
 *    ..
 * } while (0)
 *
 * do {
 *    if ((p), (int) (p)->id_len, (p)->id, (p)->id_len, (p)->cfg_line == NULL)
 *    ..
 * } while (0)
 *
 */
#define FLT_OTEL_CONF_HDR_FMT         "%p:{ { '%.*s' %zu %d } "
#define FLT_OTEL_CONF_HDR_ARGS(p,m)   (int)(p)->m##_len, (p)->m, (p)->m##_len, (p)->cfg_line

/*
 * Special two-byte prefix that triggers automatic id generation in
 * FLT_OTEL_CONF_FUNC_INIT(): the text after the prefix is combined
 * with the configuration line number to form a unique identifier.
 */
#define FLT_OTEL_CONF_HDR_SPECIAL     "\x1e\x1f"

#define FLT_OTEL_CONF_STR_CMP(s,S)    ((s##_len == S##_len) && (memcmp(s, S, S##_len) == 0))

#define FLT_OTEL_DBG_CONF_SAMPLE_EXPR(h,p) \
	OTELC_DBG(DEBUG, h "%p:{ '%s' %p }", (p), (p)->fmt_expr, (p)->expr)

#define FLT_OTEL_DBG_CONF_SAMPLE(h,p)                                             \
	OTELC_DBG(DEBUG, h "%p:{ '%s' '%s' %s %s %d %p %hhu }", (p),              \
	          (p)->key, (p)->fmt_string, otelc_value_dump(&((p)->extra), ""), \
	          flt_otel_list_dump(&((p)->exprs)), (p)->num_exprs, &((p)->lf_expr), (p)->lf_used)

#define FLT_OTEL_DBG_CONF_HDR(h,p,i) \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "}", (p), FLT_OTEL_CONF_HDR_ARGS(p, i))

#define FLT_OTEL_DBG_CONF_CONTEXT(h,p) \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "0x%02hhx }", (p), FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->flags)

#define FLT_OTEL_DBG_CONF_SPAN(h,p)                                                                           \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "'%s' %zu %s' %zu %hhu 0x%02hhx %s %s %s %s %s }", \
	                 (p), FLT_OTEL_CONF_HDR_ARGS(p, id), FLT_OTEL_STR_HDR_ARGS(p, ref_id),                \
	                 FLT_OTEL_STR_HDR_ARGS(p, ctx_id), (p)->flag_root, (p)->ctx_flags,                    \
	                 flt_otel_list_dump(&((p)->links)), flt_otel_list_dump(&((p)->attributes)),           \
	                 flt_otel_list_dump(&((p)->events)), flt_otel_list_dump(&((p)->baggages)),            \
	                 flt_otel_list_dump(&((p)->statuses)))

#define FLT_OTEL_DBG_CONF_SCOPE(h,p)                                                                        \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%hhu %d %u %s %p %s %s %s %s %s }", (p),        \
	                 FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->flag_used, (p)->event, (p)->idle_timeout,      \
	                 flt_otel_list_dump(&((p)->acls)), (p)->cond, flt_otel_list_dump(&((p)->contexts)), \
	                 flt_otel_list_dump(&((p)->spans)), flt_otel_list_dump(&((p)->spans_to_finish)),    \
	                 flt_otel_list_dump(&((p)->instruments)), flt_otel_list_dump(&((p)->log_records)))

#define FLT_OTEL_DBG_CONF_GROUP(h,p)                                         \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%hhu %s }", (p), \
	                 FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->flag_used, flt_otel_list_dump(&((p)->ph_scopes)))

#define FLT_OTEL_DBG_CONF_PH(h,p) \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%p }", (p), FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->ptr)

#define FLT_OTEL_DBG_CONF_INSTR(h,p)                                                                                         \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "'%s' %p %p %p %u %hhu %hhu 0x%02hhx %p:%s 0x%08x %u %s %s %s }", \
	                 (p), FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->config, (p)->tracer, (p)->meter, (p)->logger,              \
	                 (p)->rate_limit, (p)->flag_harderr, (p)->flag_disabled, (p)->logging, &((p)->proxy_log),            \
	                 flt_otel_list_dump(&((p)->proxy_log.loggers)), (p)->analyzers, (p)->idle_timeout,                   \
	                 flt_otel_list_dump(&((p)->acls)), flt_otel_list_dump(&((p)->ph_groups)),                            \
	                 flt_otel_list_dump(&((p)->ph_scopes)))

#define FLT_OTEL_DBG_CONF_INSTRUMENT(h,p)                                                                                     \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%" PRId64 " %d %d '%s' '%s' %s %s %p %zu %p }", (p),              \
	                 FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->idx, (p)->type, (p)->aggr_type, OTELC_STR_ARG((p)->description), \
	                 OTELC_STR_ARG((p)->unit), flt_otel_list_dump(&((p)->samples)), flt_otel_list_dump(&((p)->attributes)), \
	                 (p)->ref, (p)->bounds_num, (p)->bounds)

#define FLT_OTEL_DBG_CONF_LOG_RECORD(h,p)                                                                             \
	OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%d %" PRId64 " '%s' '%s' %s %s }", (p),                  \
	                 FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->severity, (p)->event_id, OTELC_STR_ARG((p)->event_name), \
	                 OTELC_STR_ARG((p)->span), flt_otel_list_dump(&((p)->attributes)), flt_otel_list_dump(&((p)->samples)))

#define FLT_OTEL_DBG_CONF(h,p)                                    \
	OTELC_DBG(DEBUG, h "%p:{ %p '%s' '%s' %p %s %s }", (p),   \
	          (p)->proxy, (p)->id, (p)->cfg_file, (p)->instr, \
	          flt_otel_list_dump(&((p)->groups)), flt_otel_list_dump(&((p)->scopes)))

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

/* Common header embedded in all configuration structures. */
#define FLT_OTEL_CONF_HDR(p)          \
	struct {                      \
		FLT_OTEL_CONF_STR(p); \
		int         cfg_line; \
		struct list list;     \
	}


/* Generic configuration header used for simple named list entries. */
struct flt_otel_conf_hdr {
	FLT_OTEL_CONF_HDR(id); /* A list containing header names. */
};

/* flt_otel_conf_sample->exprs */
struct flt_otel_conf_sample_expr {
	FLT_OTEL_CONF_HDR(fmt_expr); /* The original sample expression format string. */
	struct sample_expr *expr;    /* The sample expression. */
};

/*
 * flt_otel_conf_span->attributes
 * flt_otel_conf_span->events (event_name -> OTELC_VALUE_STR(&extra))
 * flt_otel_conf_span->baggages
 * flt_otel_conf_span->statuses (status_code -> extra.u.value_int32)
 * flt_otel_conf_instrument->samples
 * flt_otel_conf_log_record->samples
 */
struct flt_otel_conf_sample {
	FLT_OTEL_CONF_HDR(key);         /* The list containing sample names. */
	char               *fmt_string; /* All sample-expression arguments are combined into a single string. */
	struct otelc_value  extra;      /* Optional supplementary data. */
	struct list         exprs;      /* Used to chain sample expressions. */
	int                 num_exprs;  /* Number of defined expressions. */
	struct lf_expr      lf_expr;    /* The log-format expression. */
	bool                lf_used;    /* Whether lf_expr is used instead of exprs. */
};

/*
 * flt_otel_conf_scope->spans_to_finish
 *
 * It can be seen that this structure is actually identical to the structure
 * flt_otel_conf_hdr.
 */
struct flt_otel_conf_str {
	FLT_OTEL_CONF_HDR(str); /* A list containing character strings. */
};

/* flt_otel_conf_scope->contexts */
struct flt_otel_conf_context {
	FLT_OTEL_CONF_HDR(id); /* The name of the context. */
	uint8_t flags;         /* The type of storage from which the span context is extracted.  */
};

/* flt_otel_conf_span->links */
struct flt_otel_conf_link {
	FLT_OTEL_CONF_HDR(span); /* The list containing link names. */
};

/*
 * Span configuration within a scope.
 *   flt_otel_conf_scope->spans
 */
struct flt_otel_conf_span {
	FLT_OTEL_CONF_HDR(id);     /* The name of the span. */
	FLT_OTEL_CONF_STR(ref_id); /* The reference name, if used. */
	FLT_OTEL_CONF_STR(ctx_id); /* The span context name, if used. */
	uint8_t     ctx_flags;     /* The type of storage used for the span context. */
	bool        flag_root;     /* Whether this is a root span. */
	struct list links;         /* The set of linked span names. */
	struct list attributes;    /* The set of key:value attributes. */
	struct list events;        /* The set of events with key-value attributes. */
	struct list baggages;      /* The set of key:value baggage items. */
	struct list statuses;      /* Span status code and description (only one per list). */
};

/*
 * Metric instrument configuration within a scope.
 *   flt_otel_conf_scope->instruments
 */
struct flt_otel_conf_instrument {
	FLT_OTEL_CONF_HDR(id);                          /* The name of the instrument. */
	int64_t                            idx;         /* Meter instrument index (-1 if not yet created). */
	otelc_metric_instrument_t          type;        /* Instrument type (or UPDATE). */
	otelc_metric_aggregation_type_t    aggr_type;   /* Aggregation type for the view (create only). */
	char                              *description; /* Instrument description (create only). */
	char                              *unit;        /* Instrument unit (create only). */
	struct list                        samples;     /* Sample expressions for the value. */
	double                            *bounds;      /* Histogram bucket boundaries (create only). */
	size_t                             bounds_num;  /* Number of histogram bucket boundaries. */
	struct list                        attributes;  /* Instrument attributes (update only, flt_otel_conf_sample). */
	struct flt_otel_conf_instrument   *ref;         /* Resolved create-form instrument (update only). */
};

/*
 * Log record configuration within a scope.
 *   flt_otel_conf_scope->log_records
 */
struct flt_otel_conf_log_record {
	FLT_OTEL_CONF_HDR(id);            /* Required by macro; member <id> is not used directly. */
	otelc_log_severity_t  severity;   /* The severity level. */
	int64_t               event_id;   /* Optional event identifier. */
	char                 *event_name; /* Optional event name. */
	char                 *span;       /* Optional span reference. */
	struct list           attributes; /* Log record attributes (flt_otel_conf_sample). */
	struct list           samples;    /* Sample expressions for the body. */
};

/* Configuration for a single event scope. */
struct flt_otel_conf_scope {
	FLT_OTEL_CONF_HDR(id);            /* The scope name. */
	bool             flag_used;       /* The indication that the scope is being used. */
	int              event;           /* FLT_OTEL_EVENT_* */
	uint             idle_timeout;    /* Idle timeout interval in milliseconds (0 = off). */
	struct list      acls;            /* ACLs declared on this scope. */
	struct acl_cond *cond;            /* ACL condition to meet. */
	struct list      contexts;        /* Declared contexts. */
	struct list      spans;           /* Declared spans. */
	struct list      spans_to_finish; /* The list of spans scheduled for finishing. */
	struct list      instruments;     /* The list of metric instruments. */
	struct list      log_records;     /* The list of log records. */
};

/* Configuration for a named group of scopes. */
struct flt_otel_conf_group {
	FLT_OTEL_CONF_HDR(id); /* The group name. */
	bool        flag_used; /* The indication that the group is being used. */
	struct list ph_scopes; /* List of all used scopes. */
};

/* Placeholder referencing a scope or group by name. */
struct flt_otel_conf_ph {
	FLT_OTEL_CONF_HDR(id); /* The scope/group name. */
	void *ptr;             /* Pointer to real placeholder structure. */
};
#define flt_otel_conf_ph_group        flt_otel_conf_ph
#define flt_otel_conf_ph_scope        flt_otel_conf_ph

/* Top-level OTel instrumentation settings (tracer, meter, options). */
struct flt_otel_conf_instr {
	FLT_OTEL_CONF_HDR(id);              /* The OpenTelemetry instrumentation name. */
	char                *config;        /* The OpenTelemetry configuration file name. */
	struct otelc_tracer *tracer;        /* The OpenTelemetry tracer handle. */
	struct otelc_meter  *meter;         /* The OpenTelemetry meter handle. */
	struct otelc_logger *logger;        /* The OpenTelemetry logger handle. */
	uint32_t             rate_limit;    /* [0 2^32-1] <-> [0.0 100.0] */
	bool                 flag_harderr;  /* [0 1] */
	bool                 flag_disabled; /* [0 1] */
	uint8_t              logging;       /* [0 1 3] */
	struct proxy         proxy_log;     /* The log server list. */
	uint                 analyzers;     /* Defined channel analyzers. */
	uint                 idle_timeout;  /* Minimum idle timeout across scopes (ms, 0 = off). */
	struct list          acls;          /* ACLs declared on this tracer. */
	struct list          ph_groups;     /* List of all used groups. */
	struct list          ph_scopes;     /* List of all used scopes. */
};

/* Runtime counters for filter diagnostics. */
struct flt_otel_counters {
#ifdef DEBUG_OTEL
	struct {
		bool     flag_used; /* Whether this event is used. */
		uint64_t htx[2];    /* htx_is_empty() function result counter. */
	} event[FLT_OTEL_EVENT_MAX];
#endif

#ifdef FLT_OTEL_USE_COUNTERS
	uint64_t attached[4];       /* [run rate-limit disabled error] */
	uint64_t disabled[2];       /* How many times stream processing is disabled. */
#endif
};

/* The OpenTelemetry filter configuration. */
struct flt_otel_conf {
	struct proxy               *proxy;    /* Proxy owning the filter. */
	char                       *id;       /* The OpenTelemetry filter id. */
	char                       *cfg_file; /* The OpenTelemetry filter configuration file name. */
	struct flt_otel_conf_instr *instr;    /* The OpenTelemetry instrumentation settings. */
	struct list                 groups;   /* List of all available groups. */
	struct list                 scopes;   /* List of all available scopes. */
	struct flt_otel_counters    cnt;      /* Various counters related to filter operation. */
	struct list                 smp_args; /* Deferred OTEL sample fetch args to resolve. */
};


/* Allocate and initialize a sample from parsed arguments. */
struct flt_otel_conf_sample *flt_otel_conf_sample_init_ex(const char **args, int idx, int n, const struct otelc_value *extra, int line, struct list *head, char **err);

/* Allocate and initialize the top-level OTel filter configuration. */
struct flt_otel_conf        *flt_otel_conf_init(struct proxy *px);

/* Free the top-level OTel filter configuration. */
void                         flt_otel_conf_free(struct flt_otel_conf **ptr);

#endif /* _OTEL_CONF_H_ */

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