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

TEN-framework / ten-framework / 20163117177

12 Dec 2025 09:59AM UTC coverage: 55.763% (-0.004%) from 55.767%
20163117177

push

github

web-flow
fix: make sure log completed when python extensions crash (#1867)

* fix: make sure log completed when python extensions crash

* fix: refine code

---------

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

32 of 48 new or added lines in 2 files covered. (66.67%)

23 existing lines in 4 files now uncovered.

45896 of 82305 relevant lines covered (55.76%)

872475.56 hits per line

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

74.17
/core/src/ten_runtime/binding/python/native/ten_env/ten_env_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 <string.h>
8

9
#include "include_internal/ten_runtime/binding/python/common/error.h"
10
#include "include_internal/ten_runtime/binding/python/ten_env/ten_env.h"
11
#include "include_internal/ten_runtime/ten_env/log.h"
12
#include "ten_runtime/ten_env/internal/log.h"
13
#include "ten_utils/lib/error.h"
14
#include "ten_utils/macro/check.h"
15
#include "ten_utils/macro/memory.h"
16

17
typedef struct ten_env_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
} ten_env_notify_log_ctx_t;
26

27
static ten_env_notify_log_ctx_t *ten_env_notify_log_ctx_create(
28
    int32_t level, const char *func_name, const char *file_name, size_t line_no,
29
    const char *msg, const char *category, bool sync) {
176✔
30
  ten_env_notify_log_ctx_t *ctx = TEN_MALLOC(sizeof(ten_env_notify_log_ctx_t));
176✔
31
  TEN_ASSERT(ctx, "Failed to allocate memory.");
176✔
32

33
  ctx->level = level;
176✔
34

35
  if (sync) {
176✔
NEW
36
    ctx->completed = ten_event_create(0, 1);
×
37
  } else {
176✔
38
    ctx->completed = NULL;
176✔
39
  }
176✔
40

41
  if (func_name) {
176✔
42
    ten_string_init_from_c_str_with_size(&ctx->func_name, func_name,
176✔
43
                                         strlen(func_name));
176✔
44
  } else {
176✔
45
    TEN_STRING_INIT(ctx->func_name);
×
46
  }
×
47

48
  if (file_name) {
176✔
49
    ten_string_init_from_c_str_with_size(&ctx->file_name, file_name,
176✔
50
                                         strlen(file_name));
176✔
51
  } else {
176✔
52
    TEN_STRING_INIT(ctx->file_name);
×
53
  }
×
54

55
  ctx->line_no = line_no;
176✔
56

57
  if (msg) {
176✔
58
    ten_string_init_from_c_str_with_size(&ctx->msg, msg, strlen(msg));
176✔
59
  } else {
176✔
60
    TEN_STRING_INIT(ctx->msg);
×
61
  }
×
62

63
  if (category) {
176✔
64
    ten_string_init_from_c_str_with_size(&ctx->category, category,
40✔
65
                                         strlen(category));
40✔
66
  } else {
136✔
67
    TEN_STRING_INIT(ctx->category);
136✔
68
  }
136✔
69

70
  return ctx;
176✔
71
}
176✔
72

73
static void ten_env_notify_log_ctx_destroy(ten_env_notify_log_ctx_t *ctx) {
176✔
74
  TEN_ASSERT(ctx, "Invalid argument.");
176✔
75

76
  ten_string_deinit(&ctx->func_name);
176✔
77
  ten_string_deinit(&ctx->file_name);
176✔
78
  ten_string_deinit(&ctx->msg);
176✔
79
  ten_string_deinit(&ctx->category);
176✔
80

81
  if (ctx->completed) {
176✔
NEW
82
    ten_event_destroy(ctx->completed);
×
NEW
83
    ctx->completed = NULL;
×
NEW
84
  }
×
85

86
  TEN_FREE(ctx);
176✔
87
}
176✔
88

89
static void ten_env_proxy_notify_log(ten_env_t *ten_env, void *user_data) {
149✔
90
  TEN_ASSERT(user_data, "Invalid argument.");
149✔
91
  TEN_ASSERT(ten_env, "Should not happen.");
149✔
92
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
149✔
93

94
  ten_env_notify_log_ctx_t *ctx = user_data;
149✔
95
  TEN_ASSERT(ctx, "Should not happen.");
149✔
96

97
  ten_env_log(ten_env, ctx->level, ten_string_get_raw_str(&ctx->func_name),
149✔
98
              ten_string_get_raw_str(&ctx->file_name), ctx->line_no,
149✔
99
              ten_string_get_raw_str(&ctx->msg),
149✔
100
              ten_string_get_raw_str(&ctx->category), NULL);
149✔
101

102
  if (ctx->completed) {
149✔
NEW
103
    ten_event_set(ctx->completed);
×
104
  } else {
149✔
105
    ten_env_notify_log_ctx_destroy(ctx);
149✔
106
  }
149✔
107
}
149✔
108

109
PyObject *ten_py_ten_env_log(PyObject *self, PyObject *args) {
176✔
110
  ten_py_ten_env_t *py_ten_env = (ten_py_ten_env_t *)self;
176✔
111
  TEN_ASSERT(py_ten_env && ten_py_ten_env_check_integrity(py_ten_env),
176✔
112
             "Invalid argument.");
176✔
113

114
  if (PyTuple_GET_SIZE(args) != 7) {
176✔
115
    return ten_py_raise_py_value_error_exception(
×
116
        "Invalid argument count when ten_env.log.");
×
117
  }
×
118

119
  TEN_LOG_LEVEL level = TEN_LOG_LEVEL_INVALID;
176✔
120
  const char *func_name = NULL;
176✔
121
  const char *file_name = NULL;
176✔
122
  size_t line_no = 0;
176✔
123
  const char *msg = NULL;
176✔
124
  const char *category = NULL;
176✔
125
  bool sync = false;
176✔
126

127
  if (!PyArg_ParseTuple(args, "izzizsb", &level, &func_name, &file_name,
176✔
128
                        &line_no, &category, &msg, &sync)) {
176✔
129
    return ten_py_raise_py_value_error_exception(
×
130
        "Failed to parse argument when ten_env.log.");
×
131
  }
×
132

133
  ten_error_t err;
176✔
134
  TEN_ERROR_INIT(err);
176✔
135

136
  if (!py_ten_env->c_ten_env_proxy && !py_ten_env->c_ten_env) {
176✔
137
    ten_error_set(&err, TEN_ERROR_CODE_TEN_IS_CLOSED,
×
138
                  "ten_env.log() failed because ten is closed.");
×
139

140
    PyObject *result = (PyObject *)ten_py_error_wrap(&err);
×
141
    ten_error_deinit(&err);
×
142
    return result;
×
143
  }
×
144

145
  ten_env_notify_log_ctx_t *ctx = ten_env_notify_log_ctx_create(
176✔
146
      level, func_name, file_name, line_no, msg, category, sync);
176✔
147

148
  if (py_ten_env->c_ten_env_proxy) {
176✔
149
    if (!ten_env_proxy_notify(py_ten_env->c_ten_env_proxy,
149✔
150
                              ten_env_proxy_notify_log, ctx, false, &err)) {
149✔
151
      PyObject *result = (PyObject *)ten_py_error_wrap(&err);
×
152
      ten_error_deinit(&err);
×
153
      ten_env_notify_log_ctx_destroy(ctx);
×
154
      return result;
×
155
    }
×
156

157
    if (sync) {
149✔
NEW
158
      ten_event_wait(ctx->completed, -1);
×
NEW
159
      ten_env_notify_log_ctx_destroy(ctx);
×
NEW
160
    }
×
161
  } else {
149✔
162
    // TODO(Wei): This function is currently specifically designed for the addon
163
    // because the addon currently does not have a main thread, so it's unable
164
    // to use the ten_env_proxy mechanism to maintain thread safety. Once the
165
    // main thread for the addon is determined in the future, these hacks made
166
    // specifically for the addon can be completely removed, and comprehensive
167
    // thread safety mechanism can be implemented.
168
    TEN_ASSERT(py_ten_env->c_ten_env->attach_to == TEN_ENV_ATTACH_TO_ADDON,
27✔
169
               "Should not happen.");
27✔
170

171
    ten_env_log_without_check_thread(
27✔
172
        py_ten_env->c_ten_env, ctx->level,
27✔
173
        ten_string_get_raw_str(&ctx->func_name),
27✔
174
        ten_string_get_raw_str(&ctx->file_name), ctx->line_no,
27✔
175
        ten_string_get_raw_str(&ctx->msg),
27✔
176
        ten_string_get_raw_str(&ctx->category), NULL);
27✔
177

178
    ten_env_notify_log_ctx_destroy(ctx);
27✔
179
  }
27✔
180

181
  ten_error_deinit(&err);
176✔
182

183
  Py_RETURN_NONE;
176✔
184
}
176✔
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