ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
otel.h File Reference

Go to the source code of this file.

Data Structures

struct  ascii_otel_scope
 ascii otel scope is intentionally a small, concrete record. Fields such as scope, retained, previous give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed. More...

Macros

#define ASCII_OTEL_OPERATION(id, name, realtime)
#define ASCII_OTEL_METRIC(id, name, type, unit)
#define ASCII_OTEL_ATTR_STRING(key, value)
#define ASCII_OTEL_ATTR_INT(key, value)
#define ASCII_OTEL_PACKET(type, size, action, transport)
#define ASCII_OTEL_SCOPE_PARENT(id, parent)
#define ASCII_OTEL_SCOPE(id)

Typedefs

typedef struct ascii_otel_scope ascii_otel_scope_t
 ascii otel scope is intentionally a small, concrete record. Fields such as scope, retained, previous give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed.

Enumerations

enum  ascii_otel_operation_t { ASCII_OTEL_OPERATION_COUNT }
enum  ascii_otel_metric_t { ASCII_OTEL_METRIC_COUNT }

Functions

asciichat_error_t ascii_otel_init (const char *mode, int argc, char **argv)
void ascii_otel_shutdown (void)
bool ascii_otel_enabled (void)
const char * ascii_otel_current_operation (void)
void ascii_otel_metric (ascii_otel_metric_t metric, double value)
void ascii_otel_stats_attach (stats_scope_t *scope)
ascii_otel_metric_t ascii_otel_stats_metric (stats_record_kind_t kind, unsigned id)
void ascii_otel_ui_usage (const char *screen, const char *event, uint64_t duration_ns)
void ascii_otel_call_session_used (const char *session_string)
void ascii_otel_packet (ascii_otel_scope_t *scope, uint16_t type, size_t payload_size, const char *action, int transport)
void ascii_otel_exit (int code)
void ascii_otel_frame_rejected (const char *validator, const char *reason, size_t bytes, uint32_t width, uint32_t height, asciichat_error_t code)
gotel_context_t ascii_otel_context (void)
void ascii_otel_scope_int (ascii_otel_scope_t *scope, const char *key, int64_t value)
void ascii_otel_scope_string (ascii_otel_scope_t *scope, const char *key, const char *value)
void ascii_otel_scope_parent (ascii_otel_scope_t *scope, ascii_otel_operation_t operation, const gotel_context_t *parent)
void ascii_otel_scope_begin (ascii_otel_scope_t *scope, ascii_otel_operation_t operation)
void ascii_otel_scope_end (ascii_otel_scope_t *scope)
void ascii_otel_log (int level, const char *file, int line, const char *function, const char *format, va_list args)
void ascii_otel_error (const char *message)
void ascii_otel_error_code (asciichat_error_t code, const char *message)
ascii_otel_operation_t ascii_otel_failure_operation (asciichat_error_t code, const char *origin)
double ascii_otel_pipeline_age (uint64_t now, uint64_t capture, uint64_t progress, bool expected)
void ascii_otel_pipeline_progress (unsigned stage, unsigned expected)
void ascii_otel_http (ascii_otel_scope_t *scope, const char *hostname, const char *path)
void ascii_otel_http_status (ascii_otel_scope_t *scope, int status)
void ascii_otel_sqlite (sqlite3 *db, const gotel_query_t *queries, size_t count)
void ascii_otel_sqlite_catalog (sqlite3 *db, const gotel_query_catalog_t *catalog)
int ascii_otel_sqlite_prepare (sqlite3 *db, const char *sql, sqlite3_stmt **statement)

Macro Definition Documentation

◆ ASCII_OTEL_ATTR_INT

◆ ASCII_OTEL_ATTR_STRING

◆ ASCII_OTEL_METRIC

#define ASCII_OTEL_METRIC ( id,
name,
type,
unit )
Value:
ASCII_OTEL_METRIC_##id,

Definition at line 13 of file otel.h.

◆ ASCII_OTEL_OPERATION

#define ASCII_OTEL_OPERATION ( id,
name,
realtime )
Value:
ASCII_OTEL_##id,

Definition at line 7 of file otel.h.

◆ ASCII_OTEL_PACKET

#define ASCII_OTEL_PACKET ( type,
size,
action,
transport )
Value:
ascii_otel_packet(&otel_scope, type, size, action, transport)
deferred_action_t action
Definition actions.c:77
void ascii_otel_packet(ascii_otel_scope_t *scope, uint16_t type, size_t payload_size, const char *action, int transport)
Definition otel.c:451

Definition at line 68 of file otel.h.

Referenced by packet_receive_via_transport(), and packet_send_via_transportv().

◆ ASCII_OTEL_SCOPE

#define ASCII_OTEL_SCOPE ( id)
Value:
ascii_otel_scope_t otel_scope __attribute__((cleanup(ascii_otel_scope_end))) = {0}; \
ascii_otel_scope_begin(&otel_scope, ASCII_OTEL_##id)
int32_t vec_t __attribute__((vector_size(4 *4)))
SESSION_CREATED (PACKET_TYPE_ACIP_SESSION_CREATED) - Session created response.
Definition vector.h:42
void ascii_otel_scope_end(ascii_otel_scope_t *s)
Definition otel.c:425
struct ascii_otel_scope ascii_otel_scope_t
ascii otel scope is intentionally a small, concrete record. Fields such as scope, retained,...

Definition at line 72 of file otel.h.

72#define ASCII_OTEL_SCOPE(id) \
73 ascii_otel_scope_t otel_scope __attribute__((cleanup(ascii_otel_scope_end))) = {0}; \
74 ascii_otel_scope_begin(&otel_scope, ASCII_OTEL_##id)

Referenced by acds_on_host_announcement_ex(), acds_send_current_host(), acds_server_init(), acds_server_shutdown(), acip_client_receive_and_dispatch(), acip_outbound_create(), acip_outbound_destroy(), acip_send_ascii_frame_contract(), acip_send_audio_batch(), acip_send_audio_opus(), acip_send_audio_opus_batch(), acip_send_error(), acip_send_image_frame(), acip_send_image_frame_h265(), acip_send_ping(), acip_send_server_state(), acip_send_stream_start(), acip_send_stream_stop(), acip_server_receive_and_dispatch(), ascii_frame_init(), ascii_half_frame_init(), audio_destroy(), audio_init(), audio_start_duplex(), audio_stop_duplex(), client_audio_render_thread(), client_connection_start(), client_video_render_thread(), compress_data(), compress_workspace(), crypto_decrypt(), crypto_encrypt(), crypto_handshake_client_auth_response(), crypto_handshake_client_complete(), crypto_handshake_client_key_exchange(), crypto_handshake_server_auth_challenge(), crypto_handshake_server_complete(), crypto_handshake_server_start(), database_close(), database_init(), database_session_add_key(), database_session_cleanup_expired(), database_session_clear_host(), database_session_get_keys(), database_session_is_migration_ready(), database_session_join(), database_session_leave(), database_session_lookup(), database_session_revoke_key(), database_session_start_migration(), database_session_update_host(), database_session_verify_key(), database_stats_session_count(), database_stats_snapshot(), database_stats_unique_clients(), decompress_data(), decompress_data_exact(), discovery_session_destroy(), discovery_session_stop(), dns_test_connectivity(), ffmpeg_decoder_create_stdin(), ffmpeg_decoder_create_with_request_options(), ffmpeg_decoder_destroy(), ffmpeg_decoder_poll_video(), ffmpeg_decoder_read_audio_samples(), ffmpeg_decoder_read_video_frame(), ffmpeg_decoder_seek_to_timestamp(), h265_decode(), h265_decoder_create(), h265_encode(), h265_encoder_create(), h265_encoder_flush(), http_server_dispatch_http3(), https_get(), mcp_dispatch(), mcp_error(), media_source_create_interruptible(), media_source_destroy(), media_source_read_audio(), media_source_read_video(), media_source_rewind(), media_source_seek(), media_source_start_video(), mixer_add_source(), mixer_create_channels(), mixer_process(), mixer_process_excluding_source(), mixer_remove_source(), nat_upnp_close(), nat_upnp_open_protocol(), nat_upnp_refresh(), network_connection_open(), opus_codec_create_decoder_channels(), opus_codec_create_encoder_channels(), opus_codec_decode(), opus_codec_encode(), opus_codec_set_bitrate(), opus_codec_set_dtx(), packet_receive_via_transport(), packet_send_via_transportv(), parallel_connect(), rate_limiter_check(), rate_limiter_prune(), server_connection_init(), server_connection_lost(), server_connection_shutdown(), session_capture_create(), session_capture_destroy(), session_capture_open_media(), session_capture_open_playlist(), session_capture_process_for_transmission_into(), session_capture_read_audio(), session_capture_read_frame(), session_capture_skip_media(), session_client_like_run(), session_display_convert_to_ascii_reuse(), session_display_create(), session_display_encode_frame(), session_display_write_ascii_frame(), session_display_write_audio(), session_display_write_raw(), session_host_render_audio(), session_render_loop(), video_encoder_create(), yt_dlp_extract_with_options(), and yt_dlp_is_available().

◆ ASCII_OTEL_SCOPE_PARENT

#define ASCII_OTEL_SCOPE_PARENT ( id,
parent )
Value:
ascii_otel_scope_t otel_scope __attribute__((cleanup(ascii_otel_scope_end))) = {0}; \
ascii_otel_scope_parent(&otel_scope, ASCII_OTEL_##id, parent)

Definition at line 69 of file otel.h.

69#define ASCII_OTEL_SCOPE_PARENT(id, parent) \
70 ascii_otel_scope_t otel_scope __attribute__((cleanup(ascii_otel_scope_end))) = {0}; \
71 ascii_otel_scope_parent(&otel_scope, ASCII_OTEL_##id, parent)

Referenced by ascii_otel_call_session_used(), ascii_otel_ui_usage(), and session_pipeline_run_main().

Typedef Documentation

◆ ascii_otel_scope_t

ascii otel scope is intentionally a small, concrete record. Fields such as scope, retained, previous give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed.

Enumeration Type Documentation

◆ ascii_otel_metric_t

Enumerator
ASCII_OTEL_METRIC_COUNT 

Definition at line 12 of file otel.h.

12 {
13#define ASCII_OTEL_METRIC(id, name, type, unit) ASCII_OTEL_METRIC_##id,
14#include <ascii-chat/otel_metrics.def>
15#undef ASCII_OTEL_METRIC
ascii_otel_metric_t
Definition otel.h:12
@ ASCII_OTEL_METRIC_COUNT
Definition otel.h:16

◆ ascii_otel_operation_t

Enumerator
ASCII_OTEL_OPERATION_COUNT 

Definition at line 6 of file otel.h.

6 {
7#define ASCII_OTEL_OPERATION(id, name, realtime) ASCII_OTEL_##id,
8#include <ascii-chat/otel_operations.def>
9#undef ASCII_OTEL_OPERATION
ascii_otel_operation_t
Definition otel.h:6
@ ASCII_OTEL_OPERATION_COUNT
Definition otel.h:10

Function Documentation

◆ ascii_otel_call_session_used()

void ascii_otel_call_session_used ( const char * session_string)

Definition at line 443 of file otel.c.

443 {
444 if (!session_string || !session_string[0])
445 return;
446 // Call usage must not inherit a realtime packet's sampling decision.
447 gotel_context_t root = {0};
448 ASCII_OTEL_SCOPE_PARENT(CALL_SESSION_USED, &root);
449 ASCII_OTEL_ATTR_STRING("ascii-chat.session.string", session_string);
450}
#define ASCII_OTEL_SCOPE_PARENT(id, parent)
Definition otel.h:69
#define ASCII_OTEL_ATTR_STRING(key, value)
Definition otel.h:66

References ASCII_OTEL_ATTR_STRING, and ASCII_OTEL_SCOPE_PARENT.

◆ ascii_otel_context()

gotel_context_t ascii_otel_context ( void )

Definition at line 725 of file otel.c.

725 {
726 return gotel_current_context();
727}

Referenced by ascii_otel_error_code(), ascii_otel_frame_rejected(), and mcp_dispatch().

◆ ascii_otel_current_operation()

const char * ascii_otel_current_operation ( void )

Definition at line 153 of file otel.c.

153 {
154 return current_scope && current_scope->scope.operation < ASCII_OTEL_OPERATION_COUNT
155 ? operations[current_scope->scope.operation].name
156 : "";
157}

References ASCII_OTEL_OPERATION_COUNT.

Referenced by ascii_otel_error_code().

◆ ascii_otel_enabled()

bool ascii_otel_enabled ( void )

Definition at line 158 of file otel.c.

158 {
159 return atomic_ptr_load(&host) != NULL;
160}

Referenced by ascii_otel_error_code(), and ascii_otel_pipeline_progress().

◆ ascii_otel_error()

void ascii_otel_error ( const char * message)

Definition at line 804 of file otel.c.

804 {
805 char redacted[OTEL_BODY_BUFFER_SIZE];
806 int written = safe_snprintf(redacted, sizeof(redacted), "%s", message ? message : "");
807 if (written < 0)
808 return;
809 url_redact_diagnostic(redacted, (size_t)written >= sizeof(redacted));
810 gotel_current_error("ascii_chat.error", redacted);
811}
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
void url_redact_diagnostic(char *text, bool truncated)
Definition url.c:31
#define OTEL_BODY_BUFFER_SIZE
Definition otel.c:7

References OTEL_BODY_BUFFER_SIZE, safe_snprintf(), and url_redact_diagnostic().

Referenced by mcp_error().

◆ ascii_otel_error_code()

void ascii_otel_error_code ( asciichat_error_t code,
const char * message )

Definition at line 776 of file otel.c.

776 {
777 if (code == ASCIICHAT_OK || code == ERROR_SIGNAL_INTERRUPT || code == ERROR_NETWORK_INCOMPLETE)
778 return;
779 char redacted[OTEL_BODY_BUFFER_SIZE];
780 int written = safe_snprintf(redacted, sizeof(redacted), "%s", message ? message : "");
781 if (written < 0)
782 return;
783 url_redact_diagnostic(redacted, (size_t)written >= sizeof(redacted));
784 gotel_current_error("ascii_chat.error", redacted);
785 if (!ascii_otel_enabled())
786 return;
787 const char *origin = ascii_otel_current_operation();
789 if (operation == ASCII_OTEL_OPERATION_COUNT)
790 return;
791 const char *category = operation == ASCII_OTEL_FAILURE_CRYPTO ? "crypto"
792 : operation == ASCII_OTEL_FAILURE_PROTOCOL ? "protocol"
793 : "discovery";
794 gotel_context_t parent = ascii_otel_context();
796 if (!scope_retained(&report, operation, &parent))
797 return;
798 gotel_attr_string(&report.scope, "ascii_chat.failure.category", category);
799 gotel_attr_string(&report.scope, "ascii_chat.failure.operation", origin);
800 gotel_attr_int(&report.scope, "asciichat_errno.code", code);
801 gotel_attr_string(&report.scope, "asciichat_errno.code_message", asciichat_error_string(code));
802 gotel_error(&report.scope, category, redacted);
803}
@ ERROR_NETWORK_INCOMPLETE
Definition error_codes.h:90
@ ERROR_SIGNAL_INTERRUPT
@ ASCIICHAT_OK
Definition error_codes.h:46
bool ascii_otel_enabled(void)
Definition otel.c:158
gotel_context_t ascii_otel_context(void)
Definition otel.c:725
ascii_otel_operation_t ascii_otel_failure_operation(asciichat_error_t code, const char *origin)
Definition otel.c:763
const char * ascii_otel_current_operation(void)
Definition otel.c:153

References ascii_otel_context(), ascii_otel_current_operation(), ascii_otel_enabled(), ascii_otel_failure_operation(), ASCII_OTEL_OPERATION_COUNT, ascii_otel_scope_end(), ASCIICHAT_OK, ERROR_NETWORK_INCOMPLETE, ERROR_SIGNAL_INTERRUPT, OTEL_BODY_BUFFER_SIZE, safe_snprintf(), and url_redact_diagnostic().

◆ ascii_otel_exit()

void ascii_otel_exit ( int code)

Definition at line 736 of file otel.c.

736 {
737 gotel_attr_int(&command_scope, "process.exit.code", code);
738 if (code)
739 gotel_error(&command_scope, "ascii_chat.exit", "Command failed");
740 else {
741 command_scope.failed = false;
742 if (command_scope.span)
743 (void)otel_status(otlp_span_set_status(command_scope.span, OTLP_STATUS_CODE_UNSET, ""), "otlp_span_set_status");
744 }
745}

Referenced by main().

◆ ascii_otel_failure_operation()

ascii_otel_operation_t ascii_otel_failure_operation ( asciichat_error_t code,
const char * origin )

Definition at line 763 of file otel.c.

763 {
764 if (code == ASCIICHAT_OK || code == ERROR_SIGNAL_INTERRUPT || code == ERROR_NETWORK_INCOMPLETE)
766 if ((code >= ERROR_CRYPTO && code <= ERROR_CRYPTO_VERIFICATION) || code == ERROR_CRYPTO_INIT ||
768 return ASCII_OTEL_FAILURE_CRYPTO;
769 if (code == ERROR_NETWORK_PROTOCOL || code == ERROR_NETWORK_SIZE || code == ERROR_UNKNOWN_PACKET)
770 return ASCII_OTEL_FAILURE_PROTOCOL;
771 if ((code >= ERROR_SESSION_NOT_FOUND && code <= ERROR_SESSION_FULL) || code == ERROR_ACDS_STRING_TAKEN ||
772 code == ERROR_ACDS_STRING_INVALID || (origin && !strncmp(origin, "ascii-chat.discovery.", 21)))
773 return ASCII_OTEL_FAILURE_DISCOVERY;
775}
@ ERROR_UNKNOWN_PACKET
Definition error_codes.h:88
@ ERROR_INVALID_PASSWORD
Definition error_codes.h:83
@ ERROR_ACDS_STRING_INVALID
Definition error_codes.h:86
@ ERROR_ACDS_STRING_TAKEN
Definition error_codes.h:85
@ ERROR_CRYPTO_VERIFICATION
Definition error_codes.h:97
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_INVALID_SIGNATURE
Definition error_codes.h:84
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77
@ ERROR_SESSION_FULL
Definition error_codes.h:82
@ ERROR_CRYPTO_INIT
Definition error_codes.h:53
@ ERROR_CRYPTO
Definition error_codes.h:93
@ ERROR_SESSION_NOT_FOUND
Definition error_codes.h:81

References ASCII_OTEL_OPERATION_COUNT, ASCIICHAT_OK, ERROR_ACDS_STRING_INVALID, ERROR_ACDS_STRING_TAKEN, ERROR_CRYPTO, ERROR_CRYPTO_INIT, ERROR_CRYPTO_VERIFICATION, ERROR_INVALID_PASSWORD, ERROR_INVALID_SIGNATURE, ERROR_NETWORK_INCOMPLETE, ERROR_NETWORK_PROTOCOL, ERROR_NETWORK_SIZE, ERROR_SESSION_FULL, ERROR_SESSION_NOT_FOUND, ERROR_SIGNAL_INTERRUPT, and ERROR_UNKNOWN_PACKET.

Referenced by ascii_otel_error_code().

◆ ascii_otel_frame_rejected()

void ascii_otel_frame_rejected ( const char * validator,
const char * reason,
size_t bytes,
uint32_t width,
uint32_t height,
asciichat_error_t code )

Definition at line 746 of file otel.c.

747 {
748 ascii_otel_metric(ASCII_OTEL_METRIC_FRAME_VALIDATION_REJECTED, 1);
749 gotel_context_t parent = ascii_otel_context();
750 ascii_otel_scope_t otel_scope __attribute__((cleanup(ascii_otel_scope_end))) = {0};
751 if (!scope_retained(&otel_scope, ASCII_OTEL_FRAME_VALIDATION_REJECTED, &parent))
752 return;
753 ASCII_OTEL_ATTR_STRING("frame.validation.validator", validator);
754 ASCII_OTEL_ATTR_STRING("frame.validation.reason", reason);
755 ASCII_OTEL_ATTR_INT("frame.size_bytes", (int64_t)bytes);
756 ASCII_OTEL_ATTR_INT("frame.width", width);
757 ASCII_OTEL_ATTR_INT("frame.height", height);
758 ASCII_OTEL_ATTR_INT("asciichat_errno.code", code);
759 ASCII_OTEL_ATTR_STRING("asciichat_errno.code_message", asciichat_error_string(code));
760 if (otel_scope.retained)
761 gotel_error(&otel_scope.scope, "ascii_chat.invalid_frame", reason);
762}
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
void ascii_otel_metric(ascii_otel_metric_t metric, double value)
Definition otel.c:161
#define ASCII_OTEL_ATTR_INT(key, value)
Definition otel.h:67

References ASCII_OTEL_ATTR_INT, ASCII_OTEL_ATTR_STRING, ascii_otel_context(), ascii_otel_metric(), ascii_otel_scope_end(), height, and width.

Referenced by session_frame_validate_contract().

◆ ascii_otel_http()

void ascii_otel_http ( ascii_otel_scope_t * scope,
const char * hostname,
const char * path )

Definition at line 812 of file otel.c.

812 {
813 if (!s->retained || !hostname || !path)
814 return;
815 gotel_error(&s->scope, "http.transport", "HTTP operation did not complete");
817 int n = safe_snprintf(url, sizeof(url), "https://%s%s", hostname, path);
818 if (n >= 0 && (size_t)n < sizeof(url) &&
819 otel_status(gotel_http_name(name, sizeof(name), "ascii-chat", false, "GET", url), "Name HTTP telemetry span") ==
820 ASCIICHAT_OK) {
821 if (s->scope.span)
822 (void)otel_status(otlp_span_set_name(s->scope.span, name), "otlp_span_set_name");
823 gotel_http_attributes(&s->scope, "GET", 0);
824 gotel_attr_string(&s->scope, "server.address", hostname);
825 gotel_attr_string(&s->scope, "url.scheme", "https");
826 }
827}
#define OTEL_NAME_EXTENDED_BUFFER_SIZE
Definition otel.c:9
#define OTEL_URL_BUFFER_SIZE
Definition otel.c:8

References ASCIICHAT_OK, OTEL_NAME_EXTENDED_BUFFER_SIZE, OTEL_URL_BUFFER_SIZE, ascii_otel_scope::retained, safe_snprintf(), and ascii_otel_scope::scope.

Referenced by https_get().

◆ ascii_otel_http_status()

void ascii_otel_http_status ( ascii_otel_scope_t * scope,
int status )

Definition at line 828 of file otel.c.

828 {
829 if (s->retained) {
830 if (status > 0 && status < 400) {
831 s->scope.failed = false;
832 if (s->scope.span) {
833 (void)otel_status(otlp_span_set_status(s->scope.span, OTLP_STATUS_CODE_UNSET, ""), "otlp_span_set_status");
834 gotel_attr_string(&s->scope, "error.type", "");
835 }
836 }
837 gotel_http_attributes(&s->scope, "GET", status);
838 }
839}

References ascii_otel_scope::retained, and ascii_otel_scope::scope.

Referenced by https_get().

◆ ascii_otel_init()

asciichat_error_t ascii_otel_init ( const char * mode,
int argc,
char ** argv )

Definition at line 555 of file otel.c.

555 {
556 // Test mode is a hard export prohibition, including explicit endpoints and CLI overrides.
557 if (is_test_environment())
558 return ASCIICHAT_OK;
559 const options_t *o = options_get();
560 const char *endpoint = o->otel_endpoint;
561 if (!endpoint || endpoint[0] == '\0')
562 return ASCIICHAT_OK;
563 bool endpoint_cli = false, timeout_cli = false;
564 for (int i = 1; i < argc; ++i) {
565 endpoint_cli |= !strcmp(argv[i], "--otel-endpoint") || !strncmp(argv[i], "--otel-endpoint=", 16);
566 timeout_cli |= !strcmp(argv[i], "--otel-timeout") || !strncmp(argv[i], "--otel-timeout=", 15);
567 }
568 unsigned signals;
569 asciichat_error_t parsed = otel_status(gotel_parse_signals(o->otel_enabled_telemetry, &signals),
570 "Parse otel-enabled-telemetry (traces,logs,metrics or none)");
571 if (parsed != ASCIICHAT_OK)
572 return parsed;
574 o->otel_queue_capacity < 2 || (o->otel_queue_capacity & (o->otel_queue_capacity - 1)) || o->otel_timeout < 1 ||
576 return SET_ERRNO(ERROR_CONFIG, "Invalid telemetry sampling, queue capacity, or interval");
577 const char *log_names[] = {"dev", "debug", "info", "warn", "error", "fatal"};
578 const int log_levels[] = {LOG_DEV, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL};
579 minimum_log_level = -1;
580 for (size_t i = 0; i < sizeof(log_levels) / sizeof(log_levels[0]); ++i)
581 if (strcmp(o->otel_log_level, log_names[i]) == 0)
582 minimum_log_level = log_levels[i];
583 if (minimum_log_level < 0)
584 return SET_ERRNO(ERROR_CONFIG, "Invalid otel-log-level");
585 if (!signals)
586 return ASCIICHAT_OK;
587 gotel_options_t config = {0};
588 config.application_name = "ascii-chat";
589 config.disable_span_name_prefix = true;
590 char service_name[OPTIONS_BUFF_SIZE];
591 int n = safe_snprintf(service_name, sizeof(service_name), "ascii-chat-%s", mode);
592 if (n < 0 || (size_t)n >= sizeof(service_name))
593 return SET_ERRNO(ERROR_CONFIG, "Telemetry service name too long");
594 config.exporter.service_name = service_name;
595 // The exporter observes its batch interval during final flush as well.
596 // Keep it short enough to deliver all signals within the shutdown budget.
597 config.exporter.batch_ms = 25;
598 config.exporter.queue_capacity = (size_t)o->otel_queue_capacity;
599 config.exporter.connect_timeout_ms = (uint32_t)o->otel_timeout;
600 config.exporter.read_timeout_ms = (uint32_t)o->otel_timeout;
601 config.exporter.flush_timeout_ms = (uint32_t)o->otel_timeout;
602 otlp_resource_attr_t resources[] = {
603 {.key = "ascii_chat.mode", .value = {.type = OTLP_VALUE_STRING, .v = {.string_val = mode}}},
604 {.key = "service.version", .value = {.type = OTLP_VALUE_STRING, .v = {.string_val = ASCII_CHAT_VERSION_FULL}}},
605 };
606 config.exporter.resource_attributes = resources;
607 config.exporter.n_resource_attributes = sizeof(resources) / sizeof(resources[0]);
608 config.signals = signals;
609 config.realtime_sample_rate = o->otel_realtime_sample_rate;
610 config.realtime_max_per_second = (uint32_t)o->otel_realtime_max_per_second;
611 config.metrics_interval_ms = (uint32_t)o->otel_metrics_interval;
612 config.monotonic_ns = time_get_ns;
613 config.realtime_ns = telemetry_realtime_ns;
614 config.operations = operations;
615 config.operation_count = ASCII_OTEL_OPERATION_COUNT;
616 config.exporter_event = exporter_event;
617 config.metrics = metrics;
618 config.metric_count = ASCII_OTEL_METRIC_COUNT;
619#ifndef NDEBUG
620 config.watchdog.snapshot = watchdog_snapshot;
621 config.watchdog.decorate = watchdog_decorate;
622 config.watchdog.operation = ASCII_OTEL_THREAD_DEADLOCK;
623 config.watchdog.metric = ASCII_OTEL_METRIC_DEADLOCK_THREADS;
624#endif
625 gotel_command_args_t command_args = {0};
626 // Addresses are positional in native client/server modes, with optional ports.
627 char address_port[OPTIONS_BUFF_SIZE + 32], address6_port[OPTIONS_BUFF_SIZE + 32];
628 char address_brackets[OPTIONS_BUFF_SIZE + 32], address6_brackets[OPTIONS_BUFF_SIZE + 32];
629 char address_brackets_port[OPTIONS_BUFF_SIZE + 32], address6_brackets_port[OPTIONS_BUFF_SIZE + 32];
630 SAFE_SNPRINTF(address_port, sizeof(address_port), "%s:%d", o->address, o->port);
631 SAFE_SNPRINTF(address6_port, sizeof(address6_port), "%s:%d", o->address6, o->port);
632 SAFE_SNPRINTF(address_brackets, sizeof(address_brackets), "[%s]", o->address);
633 SAFE_SNPRINTF(address6_brackets, sizeof(address6_brackets), "[%s]", o->address6);
634 SAFE_SNPRINTF(address_brackets_port, sizeof(address_brackets_port), "[%s]:%d", o->address, o->port);
635 SAFE_SNPRINTF(address6_brackets_port, sizeof(address6_brackets_port), "[%s]:%d", o->address6, o->port);
636 const char *sensitive_values[] = {o->address, o->address6, address_port, address6_port,
637 address_brackets, address6_brackets, address_brackets_port, address6_brackets_port};
638 gotel_command_policy_t argument_policy = {
639#ifdef NDEBUG
640 .mode = GOTEL_COMMAND_REDACT_SELECTED,
641#else
642 .mode = GOTEL_COMMAND_REDACT_NONE,
643#endif
644 .rules = command_argument_rules,
645 .sensitive_values = sensitive_values,
646 .sensitive_value_count = sizeof(sensitive_values) / sizeof(sensitive_values[0]),
647 .rule_count = sizeof(command_argument_rules) / sizeof(command_argument_rules[0]),
648 };
649 asciichat_error_t arguments_status =
650 otel_status(gotel_command_args_init_policy(&command_args, "ascii-chat", mode, argc, (const char *const *)argv,
651 &argument_policy),
652 "Sanitize telemetry command arguments");
653 if (arguments_status != ASCIICHAT_OK)
654 return arguments_status;
655 config.argc = command_args.argc;
656 config.argv = command_args.argv;
657 gotel_env_storage_t env;
658 asciichat_error_t env_status =
659 otel_status(gotel_options_apply_env(&config, &env, OPT_OTEL_ENDPOINT_DEFAULT), "Configure OTEL environment");
660 if (env_status == ASCIICHAT_OK &&
661 (endpoint_cli || SAFE_GETENV("ASCII_CHAT_OTEL_ENDPOINT") || strcmp(endpoint, OPT_OTEL_ENDPOINT_DEFAULT)))
662 env_status = otel_status(gotel_options_set_endpoint(&config, &env, endpoint), "Configure telemetry endpoint");
663 if (timeout_cli || SAFE_GETENV("ASCII_CHAT_OTEL_TIMEOUT")) {
664 config.exporter.connect_timeout_ms = (uint32_t)o->otel_timeout;
665 config.exporter.read_timeout_ms = (uint32_t)o->otel_timeout;
666 config.exporter.flush_timeout_ms = (uint32_t)o->otel_timeout;
667 }
668 if (*o->otel_ca_file)
669 config.tls_ca_file = o->otel_ca_file;
670 if (env_status != ASCIICHAT_OK || !config.signals || !config.exporter.endpoint) {
671 gotel_command_args_destroy(&command_args);
672 return env_status;
673 }
674 gotel_host_t *h = NULL;
675 asciichat_error_t created = otel_status(gotel_create(&config, &h), "Initialize telemetry exporter");
676 if (created != ASCIICHAT_OK) {
677 gotel_command_args_destroy(&command_args);
678 return created;
679 }
680 gotel_set_logger(h, exporter_diagnostic, NULL);
681 shutdown_timeout_ns = (uint64_t)o->otel_timeout * NS_PER_MS_INT;
682 atomic_store(&stopping, false);
683 atomic_store(&exporter_queue_capacity, config.exporter.queue_capacity);
684 atomic_store(&worker_done, false);
685 if (platform_thread_create(&worker, "otel_export", export_worker, h) != 0) {
686 gotel_destroy(h);
687 gotel_command_args_destroy(&command_args);
688 return SET_ERRNO(ERROR_THREAD, "Cannot start telemetry exporter");
689 }
690 worker_started = true;
691 (void)atexit(ascii_otel_shutdown);
692 atomic_ptr_store(&host, h);
693 gotel_begin(h, &command_scope, ASCII_OTEL_CLI, NULL);
694 (void)otel_status(gotel_command_args_set_span(&command_scope, &command_args), "Attach telemetry command arguments");
695 gotel_command_args_destroy(&command_args);
696
697 log_info("Telemetry enabled: %s (%s)", config.exporter.endpoint, o->otel_enabled_telemetry);
698 return ASCIICHAT_OK;
699}
#define SET_ERRNO(code,...)
unsigned int uint32_t
Definition common.h:62
#define SAFE_GETENV(name)
Definition common.h:449
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:507
unsigned long long uint64_t
Definition common.h:63
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_CONFIG
Definition error_codes.h:52
@ ERROR_THREAD
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
#define NS_PER_MS_INT
Definition time.h:168
struct options_state options_t
Immutable, RCU-published snapshot of the application's runtime configuration.
#define OPT_OTEL_ENDPOINT_DEFAULT
Debug and Dev builds export to the local Spaniel Compose collector.
Definition options.h:354
const options_t * options_get(void)
Get pointer to current options struct (lock-free, thread-safe).
Definition rcu.c:511
#define OPTIONS_BUFF_SIZE
Buffer size for option string values.
Definition options.h:310
void ascii_otel_shutdown(void)
Definition otel.c:473
char otel_ca_file[256]
Definition options.h:1159
int otel_realtime_max_per_second
Definition options.h:1162
double otel_realtime_sample_rate
Definition options.h:1161
int otel_metrics_interval
Definition options.h:1163
int otel_queue_capacity
Definition options.h:1165
char otel_endpoint[256]
Definition options.h:1158
char otel_log_level[256]
Definition options.h:1157
char address6[256]
IPv6 bind address (server only).
Definition options.h:1008
int port
Server port number.
Definition options.h:1009
char otel_enabled_telemetry[256]
Definition options.h:1160
char address[256]
Server address (client) or bind address (server).
Definition options.h:1007
#define LOG_DEV
Definition types.h:38
#define LOG_DEBUG
Definition types.h:39
#define LOG_FATAL
Definition types.h:43
#define LOG_ERROR
Definition types.h:42
#define LOG_WARN
Definition types.h:41
#define LOG_INFO
Definition types.h:40

References options_state::address, options_state::address6, ASCII_OTEL_METRIC_COUNT, ASCII_OTEL_OPERATION_COUNT, ascii_otel_shutdown(), ASCIICHAT_OK, ERROR_CONFIG, ERROR_THREAD, LOG_DEBUG, LOG_DEV, LOG_ERROR, LOG_FATAL, LOG_INFO, log_info, LOG_WARN, NS_PER_MS_INT, OPT_OTEL_ENDPOINT_DEFAULT, OPTIONS_BUFF_SIZE, options_get(), options_state::otel_ca_file, options_state::otel_enabled_telemetry, options_state::otel_endpoint, options_state::otel_log_level, options_state::otel_metrics_interval, options_state::otel_queue_capacity, options_state::otel_realtime_max_per_second, options_state::otel_realtime_sample_rate, options_state::otel_timeout, options_state::port, SAFE_GETENV, SAFE_SNPRINTF, safe_snprintf(), and SET_ERRNO.

Referenced by main().

◆ ascii_otel_log()

void ascii_otel_log ( int level,
const char * file,
int line,
const char * function,
const char * format,
va_list args )

Definition at line 700 of file otel.c.

700 {
701 (void)file;
702 (void)line;
703 (void)function;
704 if (in_log || level < minimum_log_level || !atomic_ptr_load(&host))
705 return;
706 in_log = true;
707 gotel_host_t *h = retain();
708 if (h) {
709 char body[OTEL_BODY_BUFFER_SIZE];
710 int n = safe_vsnprintf(body, sizeof(body), format, args);
711 if (n >= 0) {
712 url_redact_diagnostic(body, (size_t)n >= sizeof(body));
713 otlp_severity_t severity = level >= LOG_FATAL ? OTLP_SEVERITY_FATAL
714 : level >= LOG_ERROR ? OTLP_SEVERITY_ERROR
715 : level >= LOG_WARN ? OTLP_SEVERITY_WARN
716 : level >= LOG_INFO ? OTLP_SEVERITY_INFO
717 : level >= LOG_DEBUG ? OTLP_SEVERITY_DEBUG
718 : OTLP_SEVERITY_TRACE;
719 gotel_log(h, severity, body, file, line, function);
720 }
721 release();
722 }
723 in_log = false;
724}
action_args_t args
Definition actions.c:78
int safe_vsnprintf(char *buffer, size_t buffer_size, const char *format, va_list ap)
Platform-safe vsnprintf wrapper.

References args, LOG_DEBUG, LOG_ERROR, LOG_FATAL, LOG_INFO, LOG_WARN, OTEL_BODY_BUFFER_SIZE, safe_vsnprintf(), and url_redact_diagnostic().

Referenced by log_msg().

◆ ascii_otel_metric()

◆ ascii_otel_packet()

void ascii_otel_packet ( ascii_otel_scope_t * scope,
uint16_t type,
size_t payload_size,
const char * action,
int transport )

Definition at line 451 of file otel.c.

452 {
453 if (!scope->retained || !scope->scope.span)
454 return;
455 const char *packet = acip_packet_type_name(type);
457 safe_snprintf(name, sizeof(name), "%s.%s", operations[scope->scope.operation].name, packet);
458 safe_snprintf(version, sizeof(version), "%d.%d.%d", PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR,
460 (void)otel_status(otlp_span_set_name(scope->scope.span, name), "otlp_span_set_name");
461 gotel_attr_string(&scope->scope, "network.protocol.name", "acip");
462 gotel_attr_string(&scope->scope, "network.protocol.version", version);
463 gotel_attr_string(&scope->scope, "network.packet.name", packet);
464 gotel_attr_int(&scope->scope, "network.packet.type", type);
465 gotel_attr_int(&scope->scope, "network.packet.size", (int64_t)payload_size);
466 gotel_attr_string(&scope->scope, "network.packet.operation", action);
467 const char *carrier = transport == ACIP_TRANSPORT_TCP ? "tcp"
468 : transport == ACIP_TRANSPORT_WEBSOCKET ? "websocket"
469 : transport == ACIP_TRANSPORT_WEBRTC ? "webrtc"
470 : "unknown";
471 gotel_attr_string(&scope->scope, "acip.transport", carrier);
472}
#define PROTOCOL_VERSION_MAJOR
Major protocol version number.
#define PROTOCOL_VERSION_MINOR
Minor protocol version number.
#define PROTOCOL_VERSION_PATCH
Patch protocol version number.
const char * acip_packet_type_name(uint16_t type)
Get human-readable name for packet type.
Definition handlers.c:648
@ ACIP_TRANSPORT_TCP
Raw TCP socket.
@ ACIP_TRANSPORT_WEBSOCKET
WebSocket over TCP.
@ ACIP_TRANSPORT_WEBRTC
WebRTC DataChannel (P2P).
#define OTEL_VERSION_BUFFER_SIZE
Definition otel.c:6
#define OTEL_NAME_BUFFER_SIZE
Definition otel.c:5
gotel_scope_t scope
Definition otel.h:24
bool retained
Definition otel.h:25

References acip_packet_type_name(), ACIP_TRANSPORT_TCP, ACIP_TRANSPORT_WEBRTC, ACIP_TRANSPORT_WEBSOCKET, action, OTEL_NAME_BUFFER_SIZE, OTEL_VERSION_BUFFER_SIZE, PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR, PROTOCOL_VERSION_PATCH, ascii_otel_scope::retained, safe_snprintf(), and ascii_otel_scope::scope.

◆ ascii_otel_pipeline_age()

double ascii_otel_pipeline_age ( uint64_t now,
uint64_t capture,
uint64_t progress,
bool expected )

Definition at line 296 of file otel.c.

296 {
297 return expected && capture && progress && now >= capture && now >= progress && now - capture < 2 * NS_PER_SEC_INT
298 ? (double)(now - progress) / 1e9
299 : 0;
300}
#define NS_PER_SEC_INT
Definition time.h:169

References NS_PER_SEC_INT.

◆ ascii_otel_pipeline_progress()

void ascii_otel_pipeline_progress ( unsigned stage,
unsigned expected )

Definition at line 270 of file otel.c.

270 {
271 if (!ascii_otel_enabled())
272 return;
273 uint64_t now = time_get_ns();
274 if (stage == 0) {
275 if (!atomic_load(&pipeline_capture_ns)) {
276 atomic_store(&pipeline_display_ns, now);
277 atomic_store(&pipeline_encode_ns, now);
278 }
279 if (!(expected & 1))
280 atomic_store(&pipeline_display_ns, now);
281 if (!(expected & 2))
282 atomic_store(&pipeline_encode_ns, now);
283 atomic_store(&pipeline_expected, expected);
284 atomic_store(&pipeline_capture_ns, now);
285 } else if (stage == 1)
286 atomic_store(&pipeline_display_ns, now);
287 else if (stage == 2)
288 atomic_store(&pipeline_encode_ns, now);
289 else {
290 atomic_store(&pipeline_expected, 0);
291 atomic_store(&pipeline_capture_ns, 0);
292 ascii_otel_metric(ASCII_OTEL_METRIC_PIPELINE_DISPLAY_STALL, 0);
293 ascii_otel_metric(ASCII_OTEL_METRIC_PIPELINE_ENCODE_STALL, 0);
294 }
295}

References ascii_otel_enabled(), and ascii_otel_metric().

Referenced by session_pipeline_destroy(), and session_pipeline_run_main().

◆ ascii_otel_scope_begin()

void ascii_otel_scope_begin ( ascii_otel_scope_t * scope,
ascii_otel_operation_t operation )

Definition at line 387 of file otel.c.

387 {
388 ascii_otel_scope_parent(s, op, NULL);
389}
void ascii_otel_scope_parent(ascii_otel_scope_t *s, ascii_otel_operation_t op, const gotel_context_t *parent)
Definition otel.c:390

References ascii_otel_scope_parent().

◆ ascii_otel_scope_end()

void ascii_otel_scope_end ( ascii_otel_scope_t * scope)

Definition at line 425 of file otel.c.

425 {
426 if (!s || !s->retained)
427 return;
428 gotel_end(&s->scope);
429 if (current_scope == s)
430 current_scope = s->previous;
431 s->retained = false;
432 release();
433}

References ascii_otel_scope::previous, ascii_otel_scope::retained, and ascii_otel_scope::scope.

Referenced by ascii_otel_error_code(), and ascii_otel_frame_rejected().

◆ ascii_otel_scope_int()

void ascii_otel_scope_int ( ascii_otel_scope_t * scope,
const char * key,
int64_t value )

Definition at line 728 of file otel.c.

728 {
729 if (s->retained)
730 gotel_attr_int(&s->scope, key, value);
731}

References ascii_otel_scope::retained, and ascii_otel_scope::scope.

Referenced by session_pipeline_run_main().

◆ ascii_otel_scope_parent()

void ascii_otel_scope_parent ( ascii_otel_scope_t * scope,
ascii_otel_operation_t operation,
const gotel_context_t * parent )

Definition at line 390 of file otel.c.

390 {
391 gotel_host_t *h = retain();
392 s->retained = h != NULL;
393 if (h) {
394 gotel_context_t context = gotel_current_context();
395 bool lifetime_parent = current_scope && (current_scope->scope.operation == ASCII_OTEL_SESSION_CLIENT_LIKE_RUN ||
396 current_scope->scope.operation == ASCII_OTEL_SESSION_ATTEMPT);
397 // Lifetime spans finish only at shutdown. Completed operations must remain
398 // inspectable while a server is running, including after abrupt termination.
399 if (!parent && context.valid) {
400 gotel_parent_mode_t mode =
401 lifetime_parent || memcmp(context.span_id, command_scope.context.span_id, sizeof(context.span_id)) == 0
402 ? GOTEL_PARENT_INDEPENDENT
403 : GOTEL_PARENT_BOUNDED;
404 context = gotel_operation_parent(context, mode);
405 parent = &context;
406 }
407 gotel_begin(h, &s->scope, (size_t)op, parent);
408 s->previous = current_scope;
409 current_scope = s;
410 }
411}

References ascii_otel_scope::previous, ascii_otel_scope::retained, and ascii_otel_scope::scope.

Referenced by ascii_otel_scope_begin().

◆ ascii_otel_scope_string()

void ascii_otel_scope_string ( ascii_otel_scope_t * scope,
const char * key,
const char * value )

Definition at line 732 of file otel.c.

732 {
733 if (s->retained)
734 gotel_attr_string(&s->scope, key, value);
735}

References ascii_otel_scope::retained, and ascii_otel_scope::scope.

◆ ascii_otel_shutdown()

void ascii_otel_shutdown ( void )

Definition at line 473 of file otel.c.

473 {
474 gotel_host_t *h = atomic_ptr_exchange(&host, NULL);
475 if (!h)
476 return;
477 gotel_end(&command_scope);
478 uint64_t started = time_get_ns();
479 // Leave time for the rest of process teardown, even if the collector stalls.
480 uint64_t budget_ns = shutdown_timeout_ns < 400 * NS_PER_MS_INT ? shutdown_timeout_ns : 400 * NS_PER_MS_INT;
481 while (atomic_load_explicit(&readers, memory_order_seq_cst) && time_get_ns() - started < budget_ns)
483 bool producers_active = atomic_load_explicit(&readers, memory_order_seq_cst) != 0;
484 atomic_store_explicit(&stopping, true, memory_order_release);
485 if (worker_started) {
486 while (!atomic_load_explicit(&worker_done, memory_order_acquire) && time_get_ns() - started < budget_ns)
488 bool done = atomic_load_explicit(&worker_done, memory_order_acquire);
489 uint64_t elapsed_ns = time_get_ns() - started;
490 int joined = -1;
491 if (done && elapsed_ns < budget_ns) {
492#if !defined(__linux__) && !defined(_WIN32)
493 // The POSIX timed join implementation blocks on these platforms. The worker has
494 // finished using the exporter, so detach its remaining wrapper cleanup.
495 joined = thread_detach(&worker);
496#else
497 joined = thread_join_timeout(&worker, NULL, budget_ns - elapsed_ns);
498#endif
499 }
500 if (joined != 0) {
501 log_warn("Telemetry worker did not stop within its deadline; exporter retained until process exit");
502 return;
503 }
504 worker_started = false;
505 }
506 asciichat_error_t result = drain_result;
507 otlp_exporter_stats_t stats = {0};
508 (void)otel_status(gotel_stats(h, &stats), "gotel_stats");
509 // exit() can bypass scope cleanup in a producer. Do not free its host while
510 // it remains borrowed; the process will reclaim it after atexit handlers.
511 if (!producers_active)
512 gotel_destroy(h);
513 else
514 log_warn("Telemetry producer still active during process shutdown; exporter retained");
515 if (result != ASCIICHAT_OK)
516 log_warn("Telemetry flush deadline reached; pending records discarded");
517 log_debug("Telemetry exporter stopped: spans=%llu/%llu logs=%llu/%llu metrics=%llu/%llu network_errors=%llu "
518 "http_4xx=%llu dropped=%llu rejected=%llu",
519 (unsigned long long)stats.sent, (unsigned long long)stats.emitted, (unsigned long long)stats.sent_logs,
520 (unsigned long long)stats.emitted_logs, (unsigned long long)stats.sent_metrics,
521 (unsigned long long)stats.emitted_metrics, (unsigned long long)stats.network_err,
522 (unsigned long long)stats.http_4xx, (unsigned long long)(stats.dropped_full + stats.dropped_err),
523 (unsigned long long)stats.rejected_spans);
524}
#define log_warn(...)
Log a WARN message.
Definition log/log.h:621
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.

References ASCIICHAT_OK, log_debug, log_warn, NS_PER_MS_INT, and platform_sleep_ms().

Referenced by ascii_otel_init(), and main().

◆ ascii_otel_sqlite()

void ascii_otel_sqlite ( sqlite3 * db,
const gotel_query_t * queries,
size_t count )

Definition at line 844 of file otel.c.

844 {
845 gotel_host_t *h = retain();
846 if (!h)
847 return;
848 gotel_sqlite_t *a = NULL;
849 sequel_analysis_options_t analysis = {.format = true};
850 gotel_sqlite_options_t options = {.analysis = &analysis};
851 if (otel_status(gotel_sqlite_attach_with_options(h, db, "ascii-chat.storage", queries, count, &options, &a),
852 "Attach SQLite telemetry") != ASCIICHAT_OK)
853 log_warn("Could not attach SQLite telemetry");
854 release();
855}

References ASCIICHAT_OK, and log_warn.

◆ ascii_otel_sqlite_catalog()

void ascii_otel_sqlite_catalog ( sqlite3 * db,
const gotel_query_catalog_t * catalog )

The catalog accessor and its context must remain valid until the DB closes.

Definition at line 857 of file otel.c.

857 {
858 gotel_host_t *h = retain();
859 if (!h)
860 return;
861 gotel_sqlite_t *a = NULL;
862 sequel_analysis_options_t analysis = {.format = true};
863 gotel_sqlite_options_t options = {.analysis = &analysis};
864 if (otel_status(gotel_sqlite_attach_catalog_with_options(h, db, "ascii-chat.storage", catalog, &options, &a),
865 "Attach SQLite telemetry") != ASCIICHAT_OK)
866 log_warn("Could not attach SQLite telemetry");
867 release();
868}

References ASCIICHAT_OK, and log_warn.

Referenced by database_init().

◆ ascii_otel_sqlite_prepare()

◆ ascii_otel_stats_attach()

void ascii_otel_stats_attach ( stats_scope_t * scope)

Definition at line 218 of file otel.c.

218 {
219 stats_scope_set_observer(scope, stats_metric_record, NULL);
220}
void stats_scope_set_observer(stats_scope_t *scope, stats_observer_fn observer, void *context)

References stats_scope_set_observer().

Referenced by stats_runtime_start().

◆ ascii_otel_stats_metric()

ascii_otel_metric_t ascii_otel_stats_metric ( stats_record_kind_t kind,
unsigned id )

Definition at line 181 of file otel.c.

181 {
182 if (!((kind == STATS_RECORD_COUNTER && id < STATS_COUNTER_COUNT) ||
183 (kind == STATS_RECORD_GAUGE && id < STATS_GAUGE_COUNT) ||
186 ascii_otel_metric_t metric;
187 switch (((unsigned)kind << 16) | id) {
188#define ASCII_STATS_COUNTER(id, metric_id, name, unit) \
189 case (STATS_RECORD_COUNTER << 16) | STATS_COUNTER_##id: \
190 metric = ASCII_OTEL_METRIC_##metric_id; \
191 break;
192#define ASCII_STATS_GAUGE(id, metric_id, name, unit) \
193 case (STATS_RECORD_GAUGE << 16) | STATS_GAUGE_##id: \
194 metric = ASCII_OTEL_METRIC_##metric_id; \
195 break;
196#define ASCII_STATS_DURATION(id, metric_id, name, unit) \
197 case (STATS_RECORD_DURATION << 16) | STATS_DURATION_##id: \
198 metric = ASCII_OTEL_METRIC_##metric_id; \
199 break;
200#include <ascii-chat/stats/telemetry.def>
201#undef ASCII_STATS_COUNTER
202#undef ASCII_STATS_GAUGE
203#undef ASCII_STATS_DURATION
204 default:
206 }
207 return metric;
208}

References ASCII_OTEL_METRIC_COUNT, STATS_COUNTER_COUNT, STATS_DURATION_COUNT, STATS_GAUGE_COUNT, STATS_RECORD_COUNTER, STATS_RECORD_DURATION, and STATS_RECORD_GAUGE.

◆ ascii_otel_ui_usage()

void ascii_otel_ui_usage ( const char * screen,
const char * event,
uint64_t duration_ns )

Definition at line 434 of file otel.c.

434 {
435 // UI transitions must not inherit realtime media sampling decisions.
436 gotel_context_t root = {0};
437 ASCII_OTEL_SCOPE_PARENT(UI_USAGE, &root);
438 ASCII_OTEL_ATTR_STRING("ascii_chat.ui.screen", screen);
439 ASCII_OTEL_ATTR_STRING("ascii_chat.ui.event", event);
440 ASCII_OTEL_ATTR_INT("ascii_chat.ui.duration_ns", (int64_t)duration_ns);
441}

References ASCII_OTEL_ATTR_INT, ASCII_OTEL_ATTR_STRING, and ASCII_OTEL_SCOPE_PARENT.

Referenced by keyboard_help_toggle_terminal(), log_search_enter_mode(), log_search_exit_mode(), terminal_screen_logs_handle_key_sized(), ui_error_popup_key(), ui_input_media_take(), ui_input_read_key(), update_banner_set_result(), and update_banner_toggle_overlay().