• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TEN-framework / ten-framework / 20854895930

09 Jan 2026 02:22PM UTC coverage: 58.017% (+0.3%) from 57.74%
20854895930

push

github

web-flow
feat: support log with fields (#1945)

* feat: support log with fields

* fix: refine code

* fix: refine code

* fix: refine code

* chore: test case

* feat: add macro to log with fields in c++

* fix: refine code

* fix: refine code

* feat: support log with fields in go binding

* feat: support fields in tester log

* feat: support fields in python

* feat: support fields in nodejs

* chore: update ten_gn

---------

Co-authored-by: TEN framework <ten.framework@gmail.com>
Co-authored-by: Hu Yueh-Wei <wei.hu.tw@gmail.com>

486 of 824 new or added lines in 17 files covered. (58.98%)

8 existing lines in 3 files now uncovered.

55111 of 94991 relevant lines covered (58.02%)

793596.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.95
/core/src/ten_runtime/binding/python/native/test/env_tester/env_tester_log.c
1
//
2
// Copyright © 2025 Agora
3
// This file is part of TEN Framework, an open source project.
4
// Licensed under the Apache License, Version 2.0, with certain conditions.
5
// Refer to the "LICENSE" file in the root directory for more information.
6
//
7
#include "include_internal/ten_runtime/binding/python/common/error.h"
8
#include "include_internal/ten_runtime/binding/python/test/env_tester.h"
9
#include "ten_runtime/common/error_code.h"
10
#include "ten_runtime/test/env_tester.h"
11
#include "ten_runtime/test/env_tester_proxy.h"
12
#include "ten_utils/log/log.h"
13
#include "ten_utils/macro/check.h"
14
#include "ten_utils/macro/mark.h"
15
#include "ten_utils/macro/memory.h"
16

17
typedef struct ten_env_tester_notify_log_ctx_t {
18
  int32_t level;
19
  ten_string_t func_name;
20
  ten_string_t file_name;
21
  size_t line_no;
22
  ten_string_t msg;
23
  ten_string_t category;
24
  ten_event_t *completed;
25
  uint8_t *fields_buf;
26
  size_t fields_buf_size;
27
} ten_env_tester_notify_log_ctx_t;
28

29
static ten_env_tester_notify_log_ctx_t *ten_env_tester_notify_log_ctx_create(
30
    int32_t level, const char *func_name, const char *file_name, size_t line_no,
31
    const char *msg, const char *category, bool sync, const uint8_t *fields_buf,
32
    size_t fields_buf_size) {
52✔
33
  ten_env_tester_notify_log_ctx_t *ctx =
52✔
34
      TEN_MALLOC(sizeof(ten_env_tester_notify_log_ctx_t));
52✔
35
  TEN_ASSERT(ctx, "Failed to allocate memory.");
52✔
36

37
  ctx->level = level;
52✔
38

39
  if (sync) {
52✔
40
    ctx->completed = ten_event_create(0, 1);
×
41
  } else {
52✔
42
    ctx->completed = NULL;
52✔
43
  }
52✔
44

45
  if (func_name) {
52✔
46
    ten_string_init_from_c_str_with_size(&ctx->func_name, func_name,
52✔
47
                                         strlen(func_name));
52✔
48
  } else {
52✔
49
    TEN_STRING_INIT(ctx->func_name);
×
50
  }
×
51

52
  if (file_name) {
52✔
53
    ten_string_init_from_c_str_with_size(&ctx->file_name, file_name,
52✔
54
                                         strlen(file_name));
52✔
55
  } else {
52✔
56
    TEN_STRING_INIT(ctx->file_name);
×
57
  }
×
58

59
  ctx->line_no = line_no;
52✔
60

61
  if (msg) {
52✔
62
    ten_string_init_from_c_str_with_size(&ctx->msg, msg, strlen(msg));
52✔
63
  } else {
52✔
64
    TEN_STRING_INIT(ctx->msg);
×
65
  }
×
66

67
  if (category) {
52✔
68
    ten_string_init_from_c_str_with_size(&ctx->category, category,
5✔
69
                                         strlen(category));
5✔
70
  } else {
47✔
71
    TEN_STRING_INIT(ctx->category);
47✔
72
  }
47✔
73

74
  // Copy fields buffer if provided
75
  if (fields_buf != NULL && fields_buf_size > 0) {
52✔
76
    ctx->fields_buf = TEN_MALLOC(fields_buf_size);
4✔
77
    TEN_ASSERT(ctx->fields_buf, "Failed to allocate memory for fields buffer.");
4✔
78
    memcpy(ctx->fields_buf, fields_buf, fields_buf_size);
4✔
79
    ctx->fields_buf_size = fields_buf_size;
4✔
80
  } else {
48✔
81
    ctx->fields_buf = NULL;
48✔
82
    ctx->fields_buf_size = 0;
48✔
83
  }
48✔
84

85
  return ctx;
52✔
86
}
52✔
87

88
static void ten_env_tester_notify_log_ctx_destroy(
89
    ten_env_tester_notify_log_ctx_t *ctx) {
52✔
90
  TEN_ASSERT(ctx, "Invalid argument.");
52✔
91

92
  ten_string_deinit(&ctx->func_name);
52✔
93
  ten_string_deinit(&ctx->file_name);
52✔
94
  ten_string_deinit(&ctx->msg);
52✔
95
  ten_string_deinit(&ctx->category);
52✔
96

97
  if (ctx->fields_buf != NULL) {
52✔
98
    TEN_FREE(ctx->fields_buf);
4✔
99
  }
4✔
100

101
  if (ctx->completed) {
52✔
102
    ten_event_destroy(ctx->completed);
×
103
    ctx->completed = NULL;
×
104
  }
×
105

106
  TEN_FREE(ctx);
52✔
107
}
52✔
108

109
static void ten_py_ten_env_tester_log_proxy_notify(
110
    ten_env_tester_t *ten_env_tester, void *user_data) {
52✔
111
  ten_env_tester_notify_log_ctx_t *ctx = user_data;
52✔
112
  TEN_ASSERT(ctx, "Should not happen.");
52✔
113

114
  ten_env_tester_log(
52✔
115
      ten_env_tester, ctx->level, ten_string_get_raw_str(&ctx->func_name),
52✔
116
      ten_string_get_raw_str(&ctx->file_name), ctx->line_no,
52✔
117
      ten_string_get_raw_str(&ctx->msg), ten_string_get_raw_str(&ctx->category),
52✔
118
      ctx->fields_buf, ctx->fields_buf_size, NULL);
52✔
119

120
  if (ctx->completed) {
52✔
121
    ten_event_set(ctx->completed);
×
122
  } else {
52✔
123
    ten_env_tester_notify_log_ctx_destroy(ctx);
52✔
124
  }
52✔
125
}
52✔
126

127
PyObject *ten_py_ten_env_tester_log(PyObject *self, TEN_UNUSED PyObject *args) {
53✔
128
  ten_py_ten_env_tester_t *py_ten_env_tester = (ten_py_ten_env_tester_t *)self;
53✔
129
  TEN_ASSERT(py_ten_env_tester &&
53✔
130
                 ten_py_ten_env_tester_check_integrity(py_ten_env_tester),
53✔
131
             "Invalid argument.");
53✔
132

133
  if (PyTuple_GET_SIZE(args) != 8) {
106✔
134
    return ten_py_raise_py_value_error_exception(
×
NEW
135
        "Invalid argument count when ten_env_tester.log.");
×
136
  }
×
137

138
  TEN_LOG_LEVEL level = TEN_LOG_LEVEL_INVALID;
53✔
139
  const char *func_name = NULL;
53✔
140
  const char *file_name = NULL;
53✔
141
  size_t line_no = 0;
53✔
142
  const char *category = NULL;
53✔
143
  const char *msg = NULL;
53✔
144
  bool sync = false;
53✔
145
  PyObject *fields_buf_obj = NULL;
53✔
146

147
  if (!PyArg_ParseTuple(args, "izzizsbO", &level, &func_name, &file_name,
53✔
148
                        &line_no, &category, &msg, &sync, &fields_buf_obj)) {
53✔
149
    return ten_py_raise_py_value_error_exception(
×
NEW
150
        "Failed to parse argument when ten_env_tester.log.");
×
151
  }
×
152

153
  ten_error_t err;
53✔
154
  TEN_ERROR_INIT(err);
53✔
155

156
  if (!py_ten_env_tester->c_ten_env_tester_proxy) {
53✔
157
    ten_error_set(&err, TEN_ERROR_CODE_TEN_IS_CLOSED,
1✔
158
                  "ten_env_tester.log() failed because ten is closed.");
1✔
159
    PyObject *result = (PyObject *)ten_py_error_wrap(&err);
1✔
160
    ten_error_deinit(&err);
1✔
161
    return result;
1✔
162
  }
1✔
163

164
  // Handle fields buffer
165
  const uint8_t *fields_buf = NULL;
52✔
166
  size_t fields_buf_size = 0;
52✔
167
  if (fields_buf_obj != NULL && fields_buf_obj != Py_None) {
52✔
168
    if (!PyBytes_Check(fields_buf_obj)) {
4✔
NEW
169
      return ten_py_raise_py_value_error_exception(
×
NEW
170
          "fields_buf must be bytes or None.");
×
NEW
171
    }
×
172
    fields_buf = (const uint8_t *)PyBytes_AS_STRING(fields_buf_obj);
4✔
173
    fields_buf_size = PyBytes_GET_SIZE(fields_buf_obj);
4✔
174
  }
4✔
175

176
  ten_env_tester_notify_log_ctx_t *ctx = ten_env_tester_notify_log_ctx_create(
52✔
177
      level, func_name, file_name, line_no, msg, category, sync, fields_buf,
52✔
178
      fields_buf_size);
52✔
179

180
  if (!ten_env_tester_proxy_notify(py_ten_env_tester->c_ten_env_tester_proxy,
52✔
181
                                   ten_py_ten_env_tester_log_proxy_notify, ctx,
52✔
182
                                   &err)) {
52✔
183
    PyObject *result = (PyObject *)ten_py_error_wrap(&err);
×
184
    ten_error_deinit(&err);
×
185
    ten_env_tester_notify_log_ctx_destroy(ctx);
×
186
    return result;
×
187
  }
×
188

189
  if (sync) {
52✔
190
    ten_event_wait(ctx->completed, -1);
×
191
    ten_env_tester_notify_log_ctx_destroy(ctx);
×
192
  }
×
193

194
  ten_error_deinit(&err);
52✔
195

196
  Py_RETURN_NONE;
52✔
197
}
52✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc