blob: d836a413fe62a303997429ba0e0d8550a74c8b59 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "os/mynewt.h"
#if MYNEWT_VAL(LOG_CONSOLE)
#include <cbmem/cbmem.h>
#include <console/console.h>
#include "log/log.h"
#include "tinycbor/cbor.h"
#include "tinycbor/cbor_buf_reader.h"
#include "datetime/datetime.h"
static int
log_console_dump_cbor_entry(const void *dptr, uint16_t len)
{
struct CborParser cbor_parser;
struct CborValue cbor_value;
struct cbor_buf_reader cbor_buf_reader;
cbor_buf_reader_init(&cbor_buf_reader, dptr, len);
cbor_parser_init(&cbor_buf_reader.r, 0, &cbor_parser, &cbor_value);
cbor_value_to_pretty(stdout, &cbor_value);
console_write("\n", 1);
return 0;
}
static struct log log_console;
struct log *
log_console_get(void)
{
return &log_console;
}
#if MYNEWT_VAL(LOG_CONSOLE_PRETTY)
#if MYNEWT_VAL(LOG_CONSOLE_PRETTY_WITH_COLORS)
#define ANSI_CSI "\x1b["
#define ANSI_SEP ";"
#define ANSI_CSE "m"
#define ANSI_COLOR_RESET ANSI_CSI "0" ANSI_CSE
#define COLOR_BLACK 30
#define COLOR_RED 31
#define COLOR_GREEN 32
#define COLOR_YELLOW 33
#define COLOR_BLUE 34
#define COLOR_MAGENTA 35
#define COLOR_CYAN 36
#define COLOR_WHITE 37
#define MOD_COLOR_MIN COLOR_GREEN
#define MOD_COLOR_MAX COLOR_CYAN
static void
log_module_color(uint8_t module, char *color_on, char *color_off)
{
*color_on = 0;
*color_off = 0;
if (module) {
sprintf(color_on, ANSI_CSI "%d" ANSI_SEP "%d" ANSI_CSE,
module < LOG_MODULE_PERUSER ? MYNEWT_VAL(LOG_COLOR_HILIGHT_MODULE) : 0,
MOD_COLOR_MIN + module % (MOD_COLOR_MAX - MOD_COLOR_MIN + 1));
strcpy(color_off, ANSI_COLOR_RESET);
}
}
#else
#define ANSI_CSI ""
#define ANSI_SEP ""
#define ANSI_CSE ""
#define ANSI_COLOR_RESET ""
#define log_module_color(hdr, on, off)
#endif
static const uint8_t log_level_color_code[] = {
MYNEWT_VAL(LOG_LEVEL_COLOR_CODE_DEBUG),
MYNEWT_VAL(LOG_LEVEL_COLOR_CODE_INFO),
MYNEWT_VAL(LOG_LEVEL_COLOR_CODE_WARNING),
MYNEWT_VAL(LOG_LEVEL_COLOR_CODE_ERROR),
MYNEWT_VAL(LOG_LEVEL_COLOR_CODE_CRITICAL),
/* Add new custom log levels here */
MYNEWT_VAL(LOG_LEVEL_COLOR_CODE_MAXIMUM),
};
static const char * const log_level_str[] = {
MYNEWT_VAL(LOG_LEVEL_STRING_DEBUG),
MYNEWT_VAL(LOG_LEVEL_STRING_INFO),
MYNEWT_VAL(LOG_LEVEL_STRING_WARNING),
MYNEWT_VAL(LOG_LEVEL_STRING_ERROR),
MYNEWT_VAL(LOG_LEVEL_STRING_CRITICAL),
/* Add new custom log levels here */
MYNEWT_VAL(LOG_LEVEL_STRING_MAXIMUM),
};
static const int real_log_levels = ARRAY_SIZE(log_level_str) - 1;
void
log_console_print_hdr(const struct log_entry_hdr *hdr)
{
char module_num[10];
char image_hash_str[17];
char level_str_buf[23];
const char *level_str = "";
const char *module_name = NULL;
char color[11] = "";
char color_off[6] = "";
uint8_t mapped_log_level;
uint8_t color_code;
/* Find module defined in syscfg.logcfg sections */
module_name = log_module_get_name(hdr->ue_module);
if (MYNEWT_VAL(LOG_CONSOLE_PRETTY_COLOR_MODULES)) {
log_module_color(hdr->ue_module, color, color_off);
}
if (module_name == NULL) {
module_name = module_num;
sprintf(module_num, "mod=%u", hdr->ue_module);
}
if (hdr->ue_flags & LOG_FLAGS_IMG_HASH) {
sprintf(image_hash_str, "[ih=0x%02x%02x%02x%02x]", hdr->ue_imghash[0], hdr->ue_imghash[1],
hdr->ue_imghash[2], hdr->ue_imghash[3]);
} else {
image_hash_str[0] = 0;
}
if (hdr->ue_level < real_log_levels || hdr->ue_level == LOG_LEVEL_MAX) {
mapped_log_level =
hdr->ue_level < real_log_levels ? hdr->ue_level : real_log_levels;
color_code = log_level_color_code[mapped_log_level];
if (MYNEWT_VAL(LOG_CONSOLE_PRETTY_WITH_COLORS)) {
sprintf(level_str_buf, ANSI_CSI "%d" ANSI_SEP "%d" ANSI_CSE "%s" ANSI_COLOR_RESET,
color_code >= 10 ? MYNEWT_VAL(LOG_COLOR_HILIGHT_LEVEL) : 0,
color_code % 10 + 30,
log_level_str[mapped_log_level]);
level_str = level_str_buf;
} else {
level_str = log_level_str[mapped_log_level];
}
} else {
sprintf(level_str_buf, "%-3u", hdr->ue_level);
level_str = level_str_buf;
}
if (MYNEWT_VAL(LOG_CONSOLE_PRETTY_WITH_TIMESTAMP) &&
MYNEWT_VAL(LOG_CONSOLE_PRETTY_TIMESTAMP_CLOCK)) {
struct os_timeval tv = {
.tv_usec = (unsigned int)hdr->ue_ts % 1000000,
.tv_sec = (unsigned int)(hdr->ue_ts / 1000000),
};
struct clocktime ct;
timeval_to_clocktime(&tv, NULL, &ct);
console_printf("[%d-%02d-%02dT%02d:%02d:%02d.%06u][%s%7s%s][%s]%s ",
ct.year, ct.mon, ct.day,
ct.hour, ct.min, ct.sec, ct.usec,
color, module_name, color_off, level_str, image_hash_str);
} else if (MYNEWT_VAL(LOG_CONSOLE_PRETTY_WITH_TIMESTAMP)) {
unsigned int us = (unsigned int)hdr->ue_ts % 1000000;
unsigned int s = (unsigned int)(hdr->ue_ts / 1000000);
console_printf("[%u.%06u][%s%7s%s][%s]%s ", s, us, color, module_name, color_off, level_str, image_hash_str);
} else {
console_printf("[%s%7s%s][%s]%s ", color, module_name, color_off, level_str, image_hash_str);
}
}
#else
void
log_console_print_hdr(const struct log_entry_hdr *hdr)
{
console_printf("[ts=" "%" PRIu64 "us, mod=%u level=%u ",
hdr->ue_ts, hdr->ue_module, hdr->ue_level);
if (hdr->ue_flags & LOG_FLAGS_IMG_HASH) {
console_printf("ih=0x%02x%02x%02x%02x", hdr->ue_imghash[0], hdr->ue_imghash[1],
hdr->ue_imghash[2], hdr->ue_imghash[3]);
}
console_printf("]");
}
#endif
static int
log_console_append_body(struct log *log, const struct log_entry_hdr *hdr,
const void *body, int body_len)
{
if (!console_is_init()) {
return (0);
}
if (!console_is_midline) {
log_console_print_hdr(hdr);
}
if (hdr->ue_etype != LOG_ETYPE_CBOR) {
console_write(body, body_len);
if (((const uint8_t *)body)[body_len - 1] != '\n') {
console_out('\n');
}
} else {
log_console_dump_cbor_entry(body, body_len);
}
return (0);
}
static int
log_console_append(struct log *log, void *buf, int len)
{
int hdr_len;
hdr_len = log_hdr_len(buf);
return log_console_append_body(log, buf, (uint8_t *)buf + hdr_len,
len - hdr_len);
}
static int
log_console_read(struct log *log, const void *dptr, void *buf, uint16_t offset,
uint16_t len)
{
/* You don't read console, console read you */
return (OS_EINVAL);
}
static int
log_console_walk(struct log *log, log_walk_func_t walk_func,
struct log_offset *log_offset)
{
/* You don't walk console, console walk you. */
return (OS_EINVAL);
}
static int
log_console_flush(struct log *log)
{
/* You don't flush console, console flush you. */
return (OS_EINVAL);
}
const struct log_handler log_console_handler = {
.log_type = LOG_TYPE_STREAM,
.log_read = log_console_read,
.log_append = log_console_append,
.log_append_body = log_console_append_body,
.log_walk = log_console_walk,
.log_flush = log_console_flush,
};
void
log_console_init(void)
{
int rc;
/* Ensure this function only gets called by sysinit. */
SYSINIT_ASSERT_ACTIVE();
rc = log_register("console", &log_console, &log_console_handler, NULL,
MYNEWT_VAL(LOG_LEVEL));
SYSINIT_PANIC_ASSERT(rc == 0);
}
#endif