AI改以前的轮子,除非很优秀的项目,要不然都顶不住

c 复制代码
#define _GNU_SOURCE
#include "./log.h"
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>

/* ========== 常量 ========== */
#define LOG_SLOT_SIZE 512
#define DEFAULT_RING_CAPACITY 8192 /* 必须是 2 的幂 */
#define MAX_BATCH_WRITE 256        /* writev 单次最大 iovec 数 */
#define DEFAULT_FLUSH_INTERVAL 512
#define DEFAULT_FLUSH_TIMEOUT_MS 100
#define PATH_BUF_SIZE 256
#define TIME_BUF_SIZE 20

/* slot 状态 */
enum slot_state { SLOT_FREE = 0, SLOT_WRITING = 1, SLOT_READY = 2 };

/* ========== Ring Buffer ========== */
struct log_slot {
  atomic_uint state;
  uint32_t len;
  char data[LOG_SLOT_SIZE];
};

struct ring_buffer {
  struct log_slot *slots;
  uint32_t capacity; /* 2 的幂 */
  uint32_t mask;     /* capacity - 1 */
  atomic_uint head;  /* 生产者写入位置 */
  atomic_uint tail;  /* 消费者读取位置 */
};

/* ========== Logger 结构 ========== */
struct logger {
  /* 配置 */
  const char *path;
  const char *name;
  int fd;
  enum LOG_LVL log_lvl;
  bool only_current_output;
  bool stdout_console;

  /* 异步核心 */
  struct ring_buffer rb;
  pthread_t flush_thread;
  atomic_bool running;
  pthread_mutex_t wake_mutex;
  pthread_cond_t wake_cond;

  /* 时间戳缓存 - 生产者读,后台线程写 */
  atomic_long cached_sec; /* time_t */
  char cached_time[TIME_BUF_SIZE];

  /* 轮转 */
  uint32_t threshold;
  uint32_t written;
  int32_t n_log;
  int32_t max_logs;
  char **record;
  uint32_t inner_index;

  /* flush 策略 */
  uint32_t flush_interval;
  uint32_t flush_timeout_ms;
};

/* ========== 工具函数 ========== */

static int create_dir(const char *path, int mode) {
  if (path == NULL || strlen(path) >= PATH_BUF_SIZE) {
    return -1;
  }
  char tmp[PATH_BUF_SIZE], built[PATH_BUF_SIZE];
  struct stat fst;
  memset(built, 0, sizeof(built));
  strncpy(tmp, path, sizeof(tmp) - 1);
  tmp[sizeof(tmp) - 1] = '\0';

  char *sp = tmp;
  const char *tok = NULL;
  int32_t pos = 0;
  while ((tok = strsep(&sp, "/"))) {
    if (tok[0] == '\0')
      continue;
    pos += snprintf(built + pos, sizeof(built) - pos, "/%s", tok);
    if (stat(built, &fst) != 0) {
      mkdir(built, mode);
    } else if (!S_ISDIR(fst.st_mode)) {
      if (remove(built) == 0)
        mkdir(built, mode);
    }
  }
  return 0;
}

/* 快速格式化时间戳到 buf,返回长度 */
static inline int format_time(char *buf, size_t len, const struct tm *t) {
  /* 手动格式化比 snprintf 快 ~5x */
  if (len < 15)
    return 0;
  int y = t->tm_year + 1900;
  buf[0] = '0' + (y / 1000);
  buf[1] = '0' + (y / 100 % 10);
  buf[2] = '0' + (y / 10 % 10);
  buf[3] = '0' + (y % 10);
  int m = t->tm_mon + 1;
  buf[4] = '0' + (m / 10);
  buf[5] = '0' + (m % 10);
  int d = t->tm_mday;
  buf[6] = '0' + (d / 10);
  buf[7] = '0' + (d % 10);
  int h = t->tm_hour;
  buf[8] = '0' + (h / 10);
  buf[9] = '0' + (h % 10);
  int mi = t->tm_min;
  buf[10] = '0' + (mi / 10);
  buf[11] = '0' + (mi % 10);
  int s = t->tm_sec;
  buf[12] = '0' + (s / 10);
  buf[13] = '0' + (s % 10);
  buf[14] = '\0';
  return 14;
}

/* 更新时间戳缓存(后台线程调用) */
static void update_time_cache(struct logger *dev) {
  time_t now = time(NULL);
  time_t cached = atomic_load_explicit(&dev->cached_sec, memory_order_relaxed);
  if (now != cached) {
    struct tm tminfo;
    localtime_r(&now, &tminfo);
    format_time(dev->cached_time, TIME_BUF_SIZE, &tminfo);
    atomic_store_explicit(&dev->cached_sec, now, memory_order_release);
  }
}

/* 获取缓存时间戳(生产者调用,无锁) */
static inline const char *get_cached_time(struct logger *dev) {
  return dev->cached_time;
}

/* ========== Ring Buffer 操作 ========== */

static int rb_init(struct ring_buffer *rb, uint32_t capacity) {
  /* 确保 capacity 是 2 的幂 */
  uint32_t cap = 1;
  while (cap < capacity)
    cap <<= 1;
  rb->capacity = cap;
  rb->mask = cap - 1;
  rb->slots = (struct log_slot *)calloc(cap, sizeof(struct log_slot));
  if (rb->slots == NULL)
    return -1;
  atomic_init(&rb->head, 0);
  atomic_init(&rb->tail, 0);
  for (uint32_t i = 0; i < cap; i++) {
    atomic_init(&rb->slots[i].state, SLOT_FREE);
  }
  return 0;
}

static void rb_destroy(struct ring_buffer *rb) {
  free(rb->slots);
  rb->slots = NULL;
}

/* 生产者:获取一个 slot 用于写入,返回 NULL 表示队列满 */
static struct log_slot *rb_acquire(struct ring_buffer *rb) {
  uint32_t pos =
      atomic_fetch_add_explicit(&rb->head, 1, memory_order_relaxed);
  uint32_t idx = pos & rb->mask;
  struct log_slot *slot = &rb->slots[idx];

  /* 自旋等待 slot 变为 FREE(极少触发,仅在队列满时) */
  uint32_t spin = 0;
  while (atomic_load_explicit(&slot->state, memory_order_acquire) !=
         SLOT_FREE) {
    if (++spin > 1000) {
      sched_yield();
      spin = 0;
    }
  }
  atomic_store_explicit(&slot->state, SLOT_WRITING, memory_order_relaxed);
  return slot;
}

/* 生产者:标记 slot 写入完成 */
static inline void rb_publish(struct log_slot *slot) {
  atomic_store_explicit(&slot->state, SLOT_READY, memory_order_release);
}

/* ========== 日志轮转 ========== */

static void rotate_log(struct logger *dev) {
  if (dev->fd <= 0)
    return;

  close(dev->fd);
  dev->fd = -1;

  if (dev->max_logs >= 1) {
    if (dev->n_log >= dev->max_logs) {
      for (int32_t i = 0; i < dev->max_logs; i++) {
        if (dev->record[i][0] != '\0')
          remove(dev->record[i]);
      }
      dev->n_log = 1;
      dev->inner_index = 0;
    }
  }

  char fn[PATH_BUF_SIZE], cur_fn[PATH_BUF_SIZE];
  snprintf(cur_fn, sizeof(cur_fn), "%s/%s.txt", dev->path, dev->name);
  snprintf(fn, sizeof(fn), "%s/%s.%s.txt", dev->path, dev->name,
           dev->cached_time);
  if (access(fn, F_OK) == 0) {
    snprintf(fn, sizeof(fn), "%s/%s.%s(%d).txt", dev->path, dev->name,
             dev->cached_time, dev->inner_index++);
  }
  if (dev->n_log >= 1 && dev->n_log <= dev->max_logs) {
    strncpy(dev->record[dev->n_log - 1], fn, PATH_BUF_SIZE - 1);
  }
  rename(cur_fn, fn);
  dev->n_log++;

  /* 重新打开 */
  int retry = 0;
  while (retry < 5) {
    dev->fd = open(cur_fn, O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (dev->fd >= 0)
      break;
    create_dir(dev->path, 0755);
    usleep(100000);
    retry++;
  }
  if (dev->fd < 0) {
    dev->fd = STDERR_FILENO;
  }
  dev->written = 0;
}

/* ========== 后台 Flush 线程 ========== */

static void *flush_thread_func(void *arg) {
  struct logger *dev = (struct logger *)arg;
  struct ring_buffer *rb = &dev->rb;
  struct iovec iovecs[MAX_BATCH_WRITE];

  while (atomic_load_explicit(&dev->running, memory_order_relaxed)) {
    /* 等待唤醒或超时 */
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_nsec += (long)dev->flush_timeout_ms * 1000000L;
    if (ts.tv_nsec >= 1000000000L) {
      ts.tv_sec += ts.tv_nsec / 1000000000L;
      ts.tv_nsec %= 1000000000L;
    }
    pthread_mutex_lock(&dev->wake_mutex);
    pthread_cond_timedwait(&dev->wake_cond, &dev->wake_mutex, &ts);
    pthread_mutex_unlock(&dev->wake_mutex);

    /* 更新时间戳缓存 */
    update_time_cache(dev);

    /* 批量消费 */
    uint32_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed);
    uint32_t head = atomic_load_explicit(&rb->head, memory_order_acquire);
    uint32_t count = 0;
    uint32_t batch_bytes = 0;

    while (tail != head && count < MAX_BATCH_WRITE) {
      uint32_t idx = tail & rb->mask;
      struct log_slot *slot = &rb->slots[idx];

      /* 等待 slot 变为 READY */
      if (atomic_load_explicit(&slot->state, memory_order_acquire) !=
          SLOT_READY) {
        break; /* 还在写入中,下次再处理 */
      }

      iovecs[count].iov_base = slot->data;
      iovecs[count].iov_len = slot->len;
      batch_bytes += slot->len;
      count++;
      tail++;
    }

    if (count > 0) {
      /* 检查是否需要轮转 */
      if (dev->threshold > 0 && dev->fd != STDOUT_FILENO &&
          dev->fd != STDERR_FILENO &&
          dev->written + batch_bytes >= dev->threshold) {
        rotate_log(dev);
      }

      /* writev 批量写入 */
      ssize_t n = writev(dev->fd, iovecs, count);
      (void)n;

      /* 控制台输出 */
      if (dev->stdout_console && dev->fd != STDOUT_FILENO &&
          dev->fd != STDERR_FILENO) {
        writev(STDOUT_FILENO, iovecs, count);
      }

      dev->written += batch_bytes;

      /* 释放 slots */
      uint32_t old_tail =
          atomic_load_explicit(&rb->tail, memory_order_relaxed);
      for (uint32_t i = 0; i < count; i++) {
        uint32_t idx = (old_tail + i) & rb->mask;
        rb->slots[idx].len = 0;
        atomic_store_explicit(&rb->slots[idx].state, SLOT_FREE,
                              memory_order_release);
      }
      atomic_store_explicit(&rb->tail, old_tail + count,
                            memory_order_release);
    }
  }

  /* shutdown: drain remaining */
  uint32_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed);
  uint32_t head = atomic_load_explicit(&rb->head, memory_order_acquire);
  while (tail != head) {
    uint32_t idx = tail & rb->mask;
    struct log_slot *slot = &rb->slots[idx];
    /* spin wait for READY */
    while (atomic_load_explicit(&slot->state, memory_order_acquire) !=
           SLOT_READY) {
      sched_yield();
    }
    if (slot->len > 0) {
      write(dev->fd, slot->data, slot->len);
      if (dev->stdout_console && dev->fd != STDOUT_FILENO &&
          dev->fd != STDERR_FILENO) {
        write(STDOUT_FILENO, slot->data, slot->len);
      }
    }
    atomic_store_explicit(&slot->state, SLOT_FREE, memory_order_release);
    tail++;
  }
  atomic_store_explicit(&rb->tail, tail, memory_order_release);

  if (dev->fd != STDOUT_FILENO && dev->fd != STDERR_FILENO) {
    fdatasync(dev->fd);
  }

  return NULL;
}

/* ========== 生产者:格式化 + 入队 ========== */

static const char *lvl_strings[] = {"CRIT ", "ERROR", "WARN ", "INFO ", "DEBUG"};

static inline int32_t logger_emit(struct logger *dev, enum LOG_LVL lvl,
                                  const char *file, uint32_t line,
                                  const char *func, const char *fmt,
                                  va_list ap) {
  if (dev == NULL)
    return -1;

  /* 级别检查(无锁) */
  if (dev->only_current_output) {
    if (dev->log_lvl != lvl)
      return 0;
  } else {
    if (dev->log_lvl < lvl)
      return 0;
  }

  struct log_slot *slot = rb_acquire(&dev->rb);

  /* 格式化 header */
  const char *ts = get_cached_time(dev);
  const char *lvl_str = lvl_strings[lvl];
  int pos;

  if (dev->log_lvl == DEBUG && file != NULL && func != NULL) {
    pos = snprintf(slot->data, LOG_SLOT_SIZE,
                   "[ %-14s] [ %s] [ %s] [ %s:%u] ", ts, lvl_str, func, file,
                   line);
  } else if (func != NULL) {
    pos = snprintf(slot->data, LOG_SLOT_SIZE, "[ %-14s] [ %s] [ %s] ", ts,
                   lvl_str, func);
  } else {
    pos = snprintf(slot->data, LOG_SLOT_SIZE, "[ %-14s] [ %s] ", ts, lvl_str);
  }

  if (pos < 0)
    pos = 0;
  if (pos >= (int)LOG_SLOT_SIZE)
    pos = LOG_SLOT_SIZE - 1;

  /* 格式化用户消息 */
  int msg_len =
      vsnprintf(slot->data + pos, LOG_SLOT_SIZE - pos, fmt, ap);
  if (msg_len < 0)
    msg_len = 0;
  pos += msg_len;
  if (pos >= (int)LOG_SLOT_SIZE)
    pos = LOG_SLOT_SIZE - 1;

  slot->len = pos;

  /* 发布 + 唤醒 */
  rb_publish(slot);

  /* 仅在累积一定数量后唤醒,减少 syscall */
  uint32_t head = atomic_load_explicit(&dev->rb.head, memory_order_relaxed);
  uint32_t tail = atomic_load_explicit(&dev->rb.tail, memory_order_relaxed);
  if ((head - tail) >= dev->flush_interval) {
    pthread_cond_signal(&dev->wake_cond);
  }

  return 0;
}

/* ========== 公开 API ========== */

struct logger *new_logger(const char *path, const char *name,
                          uint32_t threshold, int32_t max_logs) {
  struct logger *dev = (struct logger *)calloc(1, sizeof(struct logger));
  if (dev == NULL)
    return NULL;

  dev->path = path;
  dev->name = name;
  dev->threshold = threshold;
  dev->log_lvl = INFO;
  dev->only_current_output = false;
  dev->stdout_console = false;
  dev->flush_interval = DEFAULT_FLUSH_INTERVAL;
  dev->flush_timeout_ms = DEFAULT_FLUSH_TIMEOUT_MS;
  dev->inner_index = 1;
  dev->n_log = 1;
  dev->max_logs = max_logs;
  dev->written = 0;

  /* 轮转记录 */
  if (max_logs > 0) {
    dev->record = (char **)calloc(max_logs, sizeof(char *));
    for (int32_t i = 0; i < max_logs; i++) {
      dev->record[i] = (char *)calloc(PATH_BUF_SIZE, 1);
    }
  }

  /* 打开文件 */
  if (path == NULL) {
    dev->fd = STDOUT_FILENO;
  } else {
    create_dir(path, 0755);
    char fn[PATH_BUF_SIZE];
    snprintf(fn, sizeof(fn), "%s/%s.txt", path, name);
    dev->fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (dev->fd < 0) {
      dev->fd = STDERR_FILENO;
    }
  }

  /* 初始化 ring buffer */
  if (rb_init(&dev->rb, DEFAULT_RING_CAPACITY) != 0) {
    free(dev);
    return NULL;
  }

  /* 初始化时间戳缓存 */
  time_t now = time(NULL);
  struct tm tminfo;
  localtime_r(&now, &tminfo);
  format_time(dev->cached_time, TIME_BUF_SIZE, &tminfo);
  atomic_init(&dev->cached_sec, now);

  /* 启动后台线程 */
  pthread_mutex_init(&dev->wake_mutex, NULL);
  pthread_cond_init(&dev->wake_cond, NULL);
  atomic_init(&dev->running, true);
  pthread_create(&dev->flush_thread, NULL, flush_thread_func, dev);

  return dev;
}

void logger_free(struct logger *dev) {
  if (dev == NULL)
    return;

  /* 停止后台线程 */
  atomic_store_explicit(&dev->running, false, memory_order_release);
  pthread_cond_signal(&dev->wake_cond);
  pthread_join(dev->flush_thread, NULL);

  pthread_mutex_destroy(&dev->wake_mutex);
  pthread_cond_destroy(&dev->wake_cond);

  /* 关闭文件 */
  if (dev->fd >= 0 && dev->fd != STDOUT_FILENO && dev->fd != STDERR_FILENO) {
    close(dev->fd);
  }

  /* 释放资源 */
  rb_destroy(&dev->rb);
  if (dev->record != NULL) {
    for (int32_t i = 0; i < dev->max_logs; i++) {
      free(dev->record[i]);
    }
    free(dev->record);
  }
  free(dev);
}

int32_t logger_flush(struct logger *dev) {
  if (dev == NULL)
    return -1;
  pthread_cond_signal(&dev->wake_cond);
  /* 自旋等待队列排空 */
  uint32_t spin = 0;
  while (atomic_load_explicit(&dev->rb.head, memory_order_acquire) !=
         atomic_load_explicit(&dev->rb.tail, memory_order_acquire)) {
    if (++spin > 10000) {
      sched_yield();
      spin = 0;
    }
  }
  return 0;
}

int32_t logger_level(struct logger *dev, enum LOG_LVL lv) {
  if (dev == NULL)
    return -1;
  dev->log_lvl = lv;
  return 0;
}

int32_t logger_filter(struct logger *dev, enum LOG_LVL lv) {
  if (dev == NULL)
    return -1;
  dev->log_lvl = lv;
  dev->only_current_output = true;
  return 0;
}

int32_t logger_cancel_filter(struct logger *dev) {
  if (dev == NULL)
    return -1;
  dev->only_current_output = false;
  return 0;
}

void logger_console(struct logger *dev, bool on) {
  if (dev != NULL)
    dev->stdout_console = on;
}

int32_t logger_set_flush_interval(struct logger *dev, uint32_t count) {
  if (dev == NULL || count == 0)
    return -1;
  dev->flush_interval = count;
  return 0;
}

int32_t logger_set_flush_timeout(struct logger *dev, uint32_t ms) {
  if (dev == NULL || ms == 0)
    return -1;
  dev->flush_timeout_ms = ms;
  return 0;
}

/* ========== 日志级别 API ========== */

int32_t logger_info(struct logger *dev, const char *file, uint32_t line,
                    const char *func, const char *fmt, ...) {
  va_list arg;
  va_start(arg, fmt);
  int32_t ret = logger_emit(dev, INFO, file, line, func, fmt, arg);
  va_end(arg);
  return ret;
}

int32_t logger_warn(struct logger *dev, const char *file, uint32_t line,
                    const char *func, const char *fmt, ...) {
  va_list arg;
  va_start(arg, fmt);
  int32_t ret = logger_emit(dev, WARN, file, line, func, fmt, arg);
  va_end(arg);
  return ret;
}

int32_t logger_error(struct logger *dev, const char *file, uint32_t line,
                     const char *func, const char *fmt, ...) {
  va_list arg;
  va_start(arg, fmt);
  int32_t ret = logger_emit(dev, ERROR, file, line, func, fmt, arg);
  va_end(arg);
  return ret;
}

int32_t logger_debug(struct logger *dev, const char *file, uint32_t line,
                     const char *func, const char *fmt, ...) {
  va_list arg;
  va_start(arg, fmt);
  int32_t ret = logger_emit(dev, DEBUG, file, line, func, fmt, arg);
  va_end(arg);
  return ret;
}

int32_t logger_critical(struct logger *dev, const char *file, uint32_t line,
                        const char *func, const char *fmt, ...) {
  va_list arg;
  va_start(arg, fmt);
  int32_t ret = logger_emit(dev, CRITICAL, file, line, func, fmt, arg);
  va_end(arg);
  return ret;
}

int32_t logger_print(struct logger *dev, const char *fmt, ...) {
  if (dev == NULL)
    return -1;

  struct log_slot *slot = rb_acquire(&dev->rb);

  va_list ap;
  va_start(ap, fmt);
  int len = vsnprintf(slot->data, LOG_SLOT_SIZE, fmt, ap);
  va_end(ap);

  if (len < 0)
    len = 0;
  if (len >= (int)LOG_SLOT_SIZE)
    len = LOG_SLOT_SIZE - 1;
  slot->len = len;

  rb_publish(slot);
  return 0;
}

设计思路都很清楚,但是AI的切入点有些不同,而且质量要比人工高,以后人工写代码的时代要过去了,正如看到一个视频上讲,现在的AI 好比工业革命时的织布机,终将会替代人工去完成一些,重复的工作,刚开始的迎接的时候,就是工作经验为王了,技巧不是太重要了,人类获取的知识的途径,再一次的拉低了门槛
3年前之前花了1天写的,功能是正常的,但是在异常处理那里和指针释放没有那么仔细,写入效率偏低,现在AI-1分钟完成了代码的优化,和输出在加一个bench mark 😀
工业级软件会有一波质量级的更新
但是扎实的伦理基础关于编程还是很重要的,基础算法,编译原理,和计算机原理,都要懂才行,还是要多读书多练习,还有多掌握几门编程语言,还有各式各样的设计模式
使用原子变量,在嵌入式开发中很重要,可以构造很轻量级的线程锁,线程在嵌入式系统中有时会拖慢系统,协程和原子变量的使用,要比线程的开销小的多(这也是和AI学到的,AI联想到的更全面一些),但是又不能随意推到重来,交给AI后,重构的工作量就剩下debug了和补全AI的经验误差,Rust 这中语言,AI来写正合适,对人类来说不友好

相关推荐
安科士andxe5 小时前
深入解析|安科士1.25G CWDM SFP光模块核心技术,破解中长距离传输痛点
服务器·网络·5g
儒雅的晴天8 小时前
大模型幻觉问题
运维·服务器
通信大师9 小时前
深度解析PCC策略计费控制:核心网产品与应用价值
运维·服务器·网络·5g
默|笙11 小时前
【Linux】fd_重定向本质
linux·运维·服务器
叫我龙翔12 小时前
【计网】从零开始掌握序列化 --- JSON实现协议 + 设计 传输\会话\应用 三层结构
服务器·网络·c++·json
“αβ”12 小时前
网络层协议 -- ICMP协议
linux·服务器·网络·网络协议·icmp·traceroute·ping
wearegogog12312 小时前
基于C#的TCP/IP通信客户端与服务器
服务器·tcp/ip·c#
范纹杉想快点毕业12 小时前
C语言课后大作业项目实战,微型数据库,文件操作详解从基础到实战
服务器·数据库·microsoft
不爱学习的老登13 小时前
Windows客户端与Linux服务器配置ssh无密码登录
linux·服务器·windows
袁小皮皮不皮13 小时前
数据通信18-网络管理与运维
运维·服务器·网络·网络协议·智能路由器