mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
[log]: Normal log works on Linux now
* also removed strlcpy dependency from log * added Kconfig option for linux target Closes IDF-3245
This commit is contained in:
parent
879e6d90c2
commit
0ea20caa71
@ -361,3 +361,10 @@ test_nvs_page:
|
||||
- cd ${IDF_PATH}/components/nvs_flash/host_test/nvs_page_test
|
||||
- idf.py build
|
||||
- build/host_nvs_page_test.elf
|
||||
|
||||
test_log:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/log/host_test/log_test
|
||||
- idf.py build
|
||||
- build/test_log_host.elf
|
||||
|
4
Kconfig
4
Kconfig
@ -64,6 +64,10 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
select FREERTOS_UNICORE
|
||||
select IDF_TARGET_ARCH_RISCV
|
||||
|
||||
config IDF_TARGET_LINUX
|
||||
bool
|
||||
default "y" if IDF_TARGET="linux"
|
||||
|
||||
config IDF_FIRMWARE_CHIP_ID
|
||||
hex
|
||||
default 0x0000 if IDF_TARGET_ESP32
|
||||
|
@ -1,15 +1,23 @@
|
||||
list(APPEND srcs "log.c"
|
||||
"log_buffers.c")
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
set(srcs "log.c")
|
||||
if(${target} STREQUAL "linux")
|
||||
# We leave log buffers out for now on Linux since it's rarely used
|
||||
list(APPEND srcs "log_linux.c")
|
||||
else()
|
||||
list(APPEND srcs "log_buffers.c")
|
||||
list(APPEND priv_requires soc)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "include"
|
||||
LDFRAGMENTS linker.lf
|
||||
PRIV_REQUIRES soc)
|
||||
PRIV_REQUIRES ${priv_requires})
|
||||
|
||||
idf_build_get_property(build_components BUILD_COMPONENTS)
|
||||
# Ideally, FreeRTOS shouldn't be included into bootloader build, so the 2nd check should be unnecessary
|
||||
if(freertos IN_LIST BUILD_COMPONENTS AND NOT BOOTLOADER_BUILD)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE log_freertos.c)
|
||||
else()
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE log_noos.c)
|
||||
if(NOT ${target} STREQUAL "linux")
|
||||
# Ideally, FreeRTOS shouldn't be included into bootloader build, so the 2nd check should be unnecessary
|
||||
if(freertos IN_LIST BUILD_COMPONENTS AND NOT BOOTLOADER_BUILD)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE log_freertos.c)
|
||||
else()
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE log_noos.c)
|
||||
endif()
|
||||
endif()
|
||||
|
5
components/log/host_test/log_test/CMakeLists.txt
Normal file
5
components/log/host_test/log_test/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(COMPONENTS main)
|
||||
project(test_log_host)
|
38
components/log/host_test/log_test/README.md
Normal file
38
components/log/host_test/log_test/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
| Supported Targets | Linux |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Simple log test on Linux target
|
||||
|
||||
This unit test tests basic functionality of the log component. The test does not use mocks. Instead, it runs the whole implementation of the component on the Linux host. The test framework is CATCH.
|
||||
|
||||
*Note that the early log (ESP_EARLY_LOG<X>) functionality has not been ported to Linux since it depends on the ROM component.*
|
||||
|
||||
## Requirements
|
||||
|
||||
* A Linux system
|
||||
* The usual IDF requirements for Linux system, as described in the [Getting Started Guides](../../../../docs/en/get-started/index.rst).
|
||||
* The host's gcc/g++
|
||||
|
||||
This application has been tested on Ubuntu 20.04 with `gcc` version *9.3.0*.
|
||||
|
||||
## Build
|
||||
|
||||
First, make sure that the target is set to Linux. Run `idf.py --preview set-target linux` if you are not sure. Then do a normal IDF build: `idf.py build`.
|
||||
|
||||
## Run
|
||||
|
||||
IDF monitor doesn't work yet for Linux. You have to run the app manually:
|
||||
|
||||
```bash
|
||||
./build/test_log_host.elf
|
||||
```
|
||||
|
||||
## Example Output
|
||||
|
||||
Ideally, all tests pass, which is indicated by "All tests passed" in the last line:
|
||||
|
||||
```bash
|
||||
$ ./build/test_log_host.elf
|
||||
===============================================================================
|
||||
All tests passed (8 assertions in 6 test cases)
|
||||
```
|
5
components/log/host_test/log_test/main/CMakeLists.txt
Normal file
5
components/log/host_test/log_test/main/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
idf_component_register(SRCS "log_test.cpp"
|
||||
INCLUDE_DIRS
|
||||
"."
|
||||
$ENV{IDF_PATH}/tools/catch
|
||||
REQUIRES log)
|
141
components/log/host_test/log_test/main/log_test.cpp
Normal file
141
components/log/host_test/log_test/main/log_test.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/* LOG unit tests
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <cstdio>
|
||||
#include <regex>
|
||||
#include <iostream>
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const char *TEST_TAG = "test";
|
||||
|
||||
struct PrintFixture {
|
||||
static const size_t BUFFER_SIZE = 4096;
|
||||
|
||||
PrintFixture(esp_log_level_t log_level = ESP_LOG_VERBOSE)
|
||||
{
|
||||
if (instance != nullptr) {
|
||||
throw exception();
|
||||
}
|
||||
|
||||
std::memset(print_buffer, 0, BUFFER_SIZE);
|
||||
|
||||
instance = this;
|
||||
|
||||
old_vprintf = esp_log_set_vprintf(print_callback);
|
||||
|
||||
esp_log_level_set(TEST_TAG, log_level);
|
||||
}
|
||||
|
||||
~PrintFixture()
|
||||
{
|
||||
esp_log_level_set(TEST_TAG, ESP_LOG_INFO);
|
||||
esp_log_set_vprintf(old_vprintf);
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
string get_print_buffer_string() const
|
||||
{
|
||||
return string(print_buffer);
|
||||
}
|
||||
|
||||
void reset_buffer()
|
||||
{
|
||||
std::memset(print_buffer, 0, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
char print_buffer [BUFFER_SIZE];
|
||||
|
||||
private:
|
||||
static int print_callback(const char *format, va_list args)
|
||||
{
|
||||
return instance->print_to_buffer(format, args);
|
||||
}
|
||||
|
||||
int print_to_buffer(const char *format, va_list args)
|
||||
{
|
||||
int ret = vsnprintf(print_buffer, BUFFER_SIZE, format, args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PrintFixture *instance;
|
||||
|
||||
vprintf_like_t old_vprintf;
|
||||
};
|
||||
|
||||
PrintFixture *PrintFixture::instance = nullptr;
|
||||
|
||||
TEST_CASE("verbose log level")
|
||||
{
|
||||
PrintFixture fix(ESP_LOG_VERBOSE);
|
||||
const std::regex test_print("V \\([0-9]*\\) test: verbose", std::regex::ECMAScript);
|
||||
|
||||
ESP_LOGV(TEST_TAG, "verbose");
|
||||
CHECK(regex_search(fix.get_print_buffer_string(), test_print) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("debug log level")
|
||||
{
|
||||
PrintFixture fix(ESP_LOG_DEBUG);
|
||||
const std::regex test_print("D \\([0-9]*\\) test: debug", std::regex::ECMAScript);
|
||||
|
||||
ESP_LOGD(TEST_TAG, "debug");
|
||||
CHECK(regex_search(fix.get_print_buffer_string(), test_print) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("info log level")
|
||||
{
|
||||
PrintFixture fix(ESP_LOG_INFO);
|
||||
const std::regex test_print("I \\([0-9]*\\) test: info", std::regex::ECMAScript);
|
||||
|
||||
ESP_LOGI(TEST_TAG, "info");
|
||||
CHECK(regex_search(fix.get_print_buffer_string(), test_print) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("warn log level")
|
||||
{
|
||||
PrintFixture fix(ESP_LOG_WARN);
|
||||
const std::regex test_print("W \\([0-9]*\\) test: warn", std::regex::ECMAScript);
|
||||
|
||||
ESP_LOGW(TEST_TAG, "warn");
|
||||
CHECK(regex_search(fix.get_print_buffer_string(), test_print) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("error log level")
|
||||
{
|
||||
PrintFixture fix(ESP_LOG_ERROR);
|
||||
const std::regex test_print("E \\([0-9]*\\) test: error", std::regex::ECMAScript);
|
||||
|
||||
ESP_LOGE(TEST_TAG, "error");
|
||||
CHECK(regex_search(fix.get_print_buffer_string(), test_print) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("changing log level")
|
||||
{
|
||||
PrintFixture fix(ESP_LOG_INFO);
|
||||
const std::regex test_print("I \\([0-9]*\\) test: must indeed be printed", std::regex::ECMAScript);
|
||||
|
||||
ESP_LOGI(TEST_TAG, "must indeed be printed");
|
||||
CHECK(regex_search(fix.get_print_buffer_string(), test_print) == true);
|
||||
|
||||
fix.reset_buffer();
|
||||
esp_log_level_set(TEST_TAG, ESP_LOG_WARN);
|
||||
|
||||
ESP_LOGI(TEST_TAG, "must not be printed");
|
||||
CHECK(fix.get_print_buffer_string().size() == 0);
|
||||
|
||||
fix.reset_buffer();
|
||||
esp_log_level_set(TEST_TAG, ESP_LOG_INFO);
|
||||
|
||||
ESP_LOGI(TEST_TAG, "must indeed be printed");
|
||||
CHECK(regex_search(fix.get_print_buffer_string(), test_print) == true);
|
||||
}
|
7
components/log/host_test/log_test/sdkconfig.defaults
Normal file
7
components/log/host_test/log_test/sdkconfig.defaults
Normal file
@ -0,0 +1,7 @@
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_VERBOSE=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=5
|
||||
CONFIG_LOG_MAXIMUM_LEVEL=5
|
||||
CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
|
@ -9,8 +9,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include "esp_rom_sys.h"
|
||||
#include "sdkconfig.h"
|
||||
#if !defined(CONFIG_IDF_TARGET_LINUX)
|
||||
#include "esp_rom_sys.h"
|
||||
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -123,7 +124,7 @@ void esp_log_level_set(const char *tag, esp_log_level_t level)
|
||||
return;
|
||||
}
|
||||
new_entry->level = (uint8_t) level;
|
||||
strlcpy(new_entry->tag, tag, tag_len);
|
||||
memcpy(new_entry->tag, tag, tag_len); // we know the size and strncpy would trigger a compiler warning here
|
||||
SLIST_INSERT_HEAD(&s_log_tags, new_entry, entries);
|
||||
}
|
||||
|
||||
|
46
components/log/log_linux.c
Normal file
46
components/log/log_linux.c
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2010-2021 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// Licensed 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 <pthread.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_log_private.h"
|
||||
|
||||
static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void esp_log_impl_lock(void)
|
||||
{
|
||||
assert(pthread_mutex_lock(&mutex1) == 0);
|
||||
}
|
||||
|
||||
bool esp_log_impl_lock_timeout(void)
|
||||
{
|
||||
esp_log_impl_lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void esp_log_impl_unlock(void)
|
||||
{
|
||||
assert(pthread_mutex_unlock(&mutex1) == 0);
|
||||
}
|
||||
|
||||
uint32_t esp_log_timestamp(void)
|
||||
{
|
||||
struct timespec current_time;
|
||||
int result = clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
||||
assert(result == 0);
|
||||
uint32_t seconds = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000;
|
||||
return seconds;
|
||||
}
|
Loading…
Reference in New Issue
Block a user