From 1e494712ba3fb6d147ecd1cfd2a71f9ec08080c3 Mon Sep 17 00:00:00 2001 From: eeliu <27064129+eeliu@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:48:56 +0800 Subject: [PATCH] Pre release 0.4.13 (#563) * update common version id * add test for #562 * fix useless fail * fix backend crash --- DOC/collector-agent/readme.md | 5 +- README.md | 32 +- collector-agent/agent/GrpcAgent.go | 2 +- collector-agent/agent/UrlTemplate.go | 22 +- collector-agent/agent/UrlTemplate_test.go | 4 +- common/CMakeLists.txt | 2 +- common/include/common.h | 2 +- common/readme.md | 8 +- common/src/common.cpp | 23 +- common/test/test_common.cc | 4 + common/test/test_node.cc | 99 ++--- plugins/PY/pinpointPy/CommonPlugin.py | 8 +- plugins/PY/pinpointPy/Fastapi/test_fastapi.py | 1 + testapps/PY/app.py | 2 +- testapps/PY/templates/index.html | 2 +- testapps/backend.dockerfile | 9 +- testapps/backend/.gitignore | 9 + testapps/backend/DBControl.py | 39 ++ testapps/backend/Readme-CN.md | 32 ++ testapps/backend/Readme.md | 32 ++ testapps/backend/RedisControl.py | 26 ++ testapps/backend/__init__.py | 0 testapps/backend/app.py | 378 ++++++++++++++++++ testapps/backend/app1/user_function.py | 19 + testapps/backend/crud.py | 36 -- testapps/backend/database.py | 13 - testapps/backend/doctor.py | 12 + testapps/backend/main.py | 177 -------- testapps/backend/models.py | 26 -- testapps/backend/person.py | 10 + testapps/backend/requirements.txt | 15 +- testapps/backend/schemas.py | 37 -- testapps/backend/server.py | 8 + testapps/backend/student.py | 11 + testapps/backend/teacher.py | 12 + testapps/backend/templates/index.html | 315 +++++++++++++++ testapps/backend/test.py | 9 + testapps/backend/test_abstract.py | 20 + testapps/backend/test_args.py | 16 + testapps/backend/test_band.py | 14 + testapps/backend/test_decorator.py | 20 + testapps/backend/test_exception.py | 44 ++ testapps/backend/test_function.py | 22 + testapps/backend/test_generatior.py | 23 ++ testapps/backend/test_higher_order.py | 8 + testapps/backend/test_lambda.py | 15 + testapps/backend/test_mixin.py | 22 + testapps/backend/test_partial.py | 9 + testapps/backend/test_private.py | 15 + testapps/backend/test_recursion.py | 11 + testapps/backend/test_return.py | 14 + testapps/backend/test_returns.py | 18 + testapps/backend/test_special.py | 15 + testapps/backend/test_static_class_method.py | 17 + testapps/compose.yaml | 2 +- testapps/fastapi/main.py | 2 +- 56 files changed, 1322 insertions(+), 426 deletions(-) create mode 100644 testapps/backend/.gitignore create mode 100644 testapps/backend/DBControl.py create mode 100644 testapps/backend/Readme-CN.md create mode 100644 testapps/backend/Readme.md create mode 100644 testapps/backend/RedisControl.py delete mode 100644 testapps/backend/__init__.py create mode 100644 testapps/backend/app.py create mode 100644 testapps/backend/app1/user_function.py delete mode 100644 testapps/backend/crud.py delete mode 100644 testapps/backend/database.py create mode 100644 testapps/backend/doctor.py delete mode 100644 testapps/backend/main.py delete mode 100644 testapps/backend/models.py create mode 100644 testapps/backend/person.py delete mode 100644 testapps/backend/schemas.py create mode 100644 testapps/backend/server.py create mode 100644 testapps/backend/student.py create mode 100644 testapps/backend/teacher.py create mode 100644 testapps/backend/templates/index.html create mode 100644 testapps/backend/test.py create mode 100644 testapps/backend/test_abstract.py create mode 100644 testapps/backend/test_args.py create mode 100644 testapps/backend/test_band.py create mode 100644 testapps/backend/test_decorator.py create mode 100644 testapps/backend/test_exception.py create mode 100644 testapps/backend/test_function.py create mode 100644 testapps/backend/test_generatior.py create mode 100644 testapps/backend/test_higher_order.py create mode 100644 testapps/backend/test_lambda.py create mode 100644 testapps/backend/test_mixin.py create mode 100644 testapps/backend/test_partial.py create mode 100644 testapps/backend/test_private.py create mode 100644 testapps/backend/test_recursion.py create mode 100644 testapps/backend/test_return.py create mode 100644 testapps/backend/test_returns.py create mode 100644 testapps/backend/test_special.py create mode 100644 testapps/backend/test_static_class_method.py diff --git a/DOC/collector-agent/readme.md b/DOC/collector-agent/readme.md index ad2980f53..fb5795b37 100644 --- a/DOC/collector-agent/readme.md +++ b/DOC/collector-agent/readme.md @@ -27,11 +27,8 @@ ### Use docker images ```sh -docker run -itd -p 9999:9999 --env-file ./env.list ghcr.io/pinpoint-apm/pinpoint-c-agent/collector-agent:latest +docker run -itd -p 9999:9999 --env-file ./env.list ghcr.io/pinpoint-apm/pinpoint-c-agent/collector-agent:0.4.25 ``` -> Collector Agent Span Specification - -[Json string map to Pinpoint item](../API/collector-agent/Readme.md) diff --git a/README.md b/README.md index 402aeb29d..f452bb1e5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![pinpoint](images/logo.png) -[![Build](https://github.com/pinpoint-apm/pinpoint-c-agent/workflows/Build/badge.svg?branch=master)](https://github.com/pinpoint-apm/pinpoint-c-agent/actions) [![Gitter](https://badges.gitter.im/naver/pinpoint-c-agent.svg)](https://gitter.im/naver/pinpoint-c-agent?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![codecov](https://codecov.io/gh/pinpoint-apm/pinpoint-c-agent/branch/master/graph/badge.svg?token=KswbmFvWp3)](https://codecov.io/gh/pinpoint-apm/pinpoint-c-agent) [![License](https://img.shields.io/github/license/pinpoint-apm/pinpoint-c-agent)](LICENSE) +[![CI](https://github.com/pinpoint-apm/pinpoint-c-agent/actions/workflows/main.yml/badge.svg)](https://github.com/pinpoint-apm/pinpoint-c-agent/actions/workflows/main.yml) [![Gitter](https://badges.gitter.im/naver/pinpoint-c-agent.svg)](https://gitter.im/naver/pinpoint-c-agent?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![codecov](https://codecov.io/gh/pinpoint-apm/pinpoint-c-agent/branch/master/graph/badge.svg?token=KswbmFvWp3)](https://codecov.io/gh/pinpoint-apm/pinpoint-c-agent) [![License](https://img.shields.io/github/license/pinpoint-apm/pinpoint-c-agent)](LICENSE) @@ -9,42 +9,18 @@ The current stable version is [the Latest](https://github.com/pinpoint-apm/pinpoint-c-agent/releases). -# Pinpoint Common Agent +# Pinpoint Agent It is an agent written by C++, PHP and Python languages. And we hope to support other languages by this agent. Until now, it supports **_PHP_**, **_C/CPP_** and **_PYTHON_**. -## Overview Pinpoint Common Agent +## Overview Pinpoint Agent ### How does it work ![How does it work](images/pinpoint_v0.5.x.png) -### Distributed Tracking system - -![php_agent_example](images/php_agent_example.png) - -### Call Stack - -![php_agent_example_detail](images/php_agent_example_detail.png) | ![php_agent_example_memcached](images/callstack-memcached.png) ---- | --- -![php_agent_example_pdo](images/callstack-pdo.png) | ![php_agent_example_redis](images/callstack-redis.png) - -### Real-time Tracking Chart - - CPU | Response Time - --- | --- - ![php_agent_example_pdo](images/cpu.png) | ![php_agent_example_redis](images/responsetime.png) - - ## Installation guide -**Components:** -* Collector-Agent (**Required**) -* PHP-Agent -* Python-Agent -* c/cpp Agent -* Golang-Agent - ### Install Collector-Agent [How to install Collector-Agent](DOC/collector-agent/readme.md) @@ -80,8 +56,6 @@ golang|[go-aop-agent](https://github.com/pinpoint-apm/go-aop-agent) We are looking forward to your contributions via pull requests. -https://github.com/pinpoint-apm/pinpoint-c-agent/graphs/contributors - ## License This project is licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for full license text. diff --git a/collector-agent/agent/GrpcAgent.go b/collector-agent/agent/GrpcAgent.go index 9ddbacff9..9c6724dd7 100644 --- a/collector-agent/agent/GrpcAgent.go +++ b/collector-agent/agent/GrpcAgent.go @@ -237,7 +237,7 @@ func (agent *GrpcAgent) sendStat() { wg.Add(1) go func() { for { - msg := agent.utReport.MoveUtReprot() + msg := agent.utReport.MoveUtReport() agent.log.Debugf("%v", msg) if err := stream.Send(msg); err != nil { diff --git a/collector-agent/agent/UrlTemplate.go b/collector-agent/agent/UrlTemplate.go index 0748d126d..c3e816469 100644 --- a/collector-agent/agent/UrlTemplate.go +++ b/collector-agent/agent/UrlTemplate.go @@ -26,7 +26,7 @@ func (ust *uriStatHistogram) Update(span *TSpan) { ust.TimestampHistogram[span.FindHistogramLevel()] += 1 } -func (ust *uriStatHistogram) ToUriHistogrm() *v1.PUriHistogram { +func (ust *uriStatHistogram) ToUriHistogram() *v1.PUriHistogram { pbUriHistogram := &v1.PUriHistogram{ Total: ust.Total, Max: ust.Max, @@ -35,12 +35,12 @@ func (ust *uriStatHistogram) ToUriHistogrm() *v1.PUriHistogram { return pbUriHistogram } -type statHisograms struct { +type statHistograms struct { TotalHistogram uriStatHistogram FailedHistogram uriStatHistogram } -func (st *statHisograms) Update(span *TSpan) { +func (st *statHistograms) Update(span *TSpan) { st.TotalHistogram.Update(span) if span.IsFailed() { st.FailedHistogram.Update(span) @@ -48,7 +48,7 @@ func (st *statHisograms) Update(span *TSpan) { } type UrlTemplateReport struct { - uriMap map[string]*statHisograms + uriMap map[string]*statHistograms BucketVersion int32 mu sync.Mutex } @@ -65,16 +65,16 @@ func (utr *UrlTemplateReport) updateUriSnapshot(span *TSpan) { utr.mu.Lock() defer utr.mu.Unlock() ut := span.UT - var st *statHisograms + var st *statHistograms var ok bool if st, ok = utr.uriMap[ut]; !ok { - st = &statHisograms{} + st = &statHistograms{} utr.uriMap[ut] = st } st.Update(span) } -func (utr *UrlTemplateReport) MoveUtReprot() *v1.PStatMessage { +func (utr *UrlTemplateReport) MoveUtReport() *v1.PStatMessage { utr.mu.Lock() defer utr.mu.Unlock() @@ -85,14 +85,14 @@ func (utr *UrlTemplateReport) MoveUtReprot() *v1.PStatMessage { for url, st := range utr.uriMap { eachUriStat := &v1.PEachUriStat{ Uri: url, - TotalHistogram: st.TotalHistogram.ToUriHistogrm(), - FailedHistogram: st.FailedHistogram.ToUriHistogrm(), + TotalHistogram: st.TotalHistogram.ToUriHistogram(), + FailedHistogram: st.FailedHistogram.ToUriHistogram(), Timestamp: time.Now().UnixMilli(), } agentUriStat.EachUriStat = append(agentUriStat.EachUriStat, eachUriStat) } //note: create a new one - utr.uriMap = make(map[string]*statHisograms) + utr.uriMap = make(map[string]*statHistograms) pbStat := &v1.PStatMessage{ Field: &v1.PStatMessage_AgentUriStat{ AgentUriStat: agentUriStat, @@ -104,7 +104,7 @@ func (utr *UrlTemplateReport) MoveUtReprot() *v1.PStatMessage { func CreateUrlTemplateReport() *UrlTemplateReport { ut := &UrlTemplateReport{ - uriMap: make(map[string]*statHisograms), + uriMap: make(map[string]*statHistograms), BucketVersion: bucketVersion, } return ut diff --git a/collector-agent/agent/UrlTemplate_test.go b/collector-agent/agent/UrlTemplate_test.go index a483624cc..8ed71d33d 100644 --- a/collector-agent/agent/UrlTemplate_test.go +++ b/collector-agent/agent/UrlTemplate_test.go @@ -40,7 +40,7 @@ func TestUrlTemplateReport(t *testing.T) { t.Log(len(ut.uriMap)) } - pbStatMessage := ut.MoveUtReprot() + pbStatMessage := ut.MoveUtReport() t.Log(pbStatMessage) assert.NotEqual(t, pbStatMessage.GetAgentUriStat(), nil, "GetAgentUriStat") @@ -57,6 +57,6 @@ func TestUrlTemplateReport(t *testing.T) { totalHis := eachUriStat[0].GetTotalHistogram() assert.Equal(t, len(totalHis.GetHistogram()), histogramSize, "len(totalHis.GetHistogram())") - assert.Equal(t, totalHis.Max, int64(3200), "totalHis.Max") + assert.GreaterOrEqual(t, totalHis.Max, int64(3200), "totalHis.Max") } diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e1b9fa95e..0ac94d550 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.13) -project(pinpoint VERSION 0.4.24 DESCRIPTION "pinpoint common library") +project(pinpoint VERSION 0.4.25 DESCRIPTION "pinpoint common library") set(CMAKE_CXX_STANDARD 11) diff --git a/common/include/common.h b/common/include/common.h index 9bb39bd09..3a9265058 100644 --- a/common/include/common.h +++ b/common/include/common.h @@ -93,7 +93,7 @@ static const NodeID E_ROOT_NODE = 0; static const E_NODE_LOC E_LOC_CURRENT = 0x0; static const E_NODE_LOC E_LOC_ROOT = 0x1; -#define PINPOINT_C_AGENT_API_VERSION "0.4.24" +#define PINPOINT_C_AGENT_API_VERSION "0.4.25" /** * @brief change logs diff --git a/common/readme.md b/common/readme.md index e0c0b0aff..2122e0afb 100644 --- a/common/readme.md +++ b/common/readme.md @@ -5,4 +5,10 @@ ```shell $ cmake -DWITH_TEST_CASE=1 -DWITH_CODECOVERAGE=1 -DCMAKE_BUILD_TYPE=Debug .. $ ./bin/TestCommon --gtest_filter=node.wakeTrace -``` \ No newline at end of file +``` + +## Changes + +- 2023/11/23 + - support FetchContent #561 + diff --git a/common/src/common.cpp b/common/src/common.cpp index 990492fa2..e2470979d 100644 --- a/common/src/common.cpp +++ b/common/src/common.cpp @@ -182,22 +182,15 @@ int pinpoint_wake_trace(NodeID traceId) { } int pinpoint_force_end_trace(NodeID id, int32_t timeout) { - try { - _span_timeout = timeout; - while (id != E_ROOT_NODE) { - id = pinpoint_end_trace(id); - if (id == E_INVALID_NODE) - break; - } - // back to normal - _span_timeout = global_agent_info.timeout_ms; - return 0; - } catch (const std::out_of_range&) { - pp_trace(" [%d] not found", id); - } catch (const std::exception& ex) { - pp_trace(" [%d] end trace failed. %s", id, ex.what()); + _span_timeout = timeout; + while (id != E_ROOT_NODE) { + id = pinpoint_end_trace(id); + if (id == E_INVALID_NODE) + break; } - return -1; + // back to normal + _span_timeout = global_agent_info.timeout_ms; + return 0; } int pinpoint_trace_is_root(NodeID _id) { diff --git a/common/test/test_common.cc b/common/test/test_common.cc index 2a1b97e4e..b82106e6a 100644 --- a/common/test/test_common.cc +++ b/common/test/test_common.cc @@ -54,6 +54,10 @@ TEST(common, start_end_trace) { id = pinpoint_end_trace(id); EXPECT_EQ(id, 0); + mark_current_trace_status(-1024, E_TRACE_BLOCK); + mark_current_trace_status(1024, E_TRACE_BLOCK); + catch_error(-1024, "sdfasfas", "fsafdsfasd", 234); + catch_error(0, "sdfasfas", "fsafdsfasd", 234); } TEST(common, context_check) { diff --git a/common/test/test_node.cc b/common/test/test_node.cc index 4d9abf046..9115de7bf 100644 --- a/common/test/test_node.cc +++ b/common/test/test_node.cc @@ -18,11 +18,13 @@ std::mutex cv_m; std::condition_variable cv; NodeID rootId = E_ROOT_NODE; -int usedNode() { return PoolManager::getInstance().totoalNodesCount() - PoolManager::getInstance().freeNodesCount(); } +int usedNode() { + return PoolManager::getInstance().totoalNodesCount() - + PoolManager::getInstance().freeNodesCount(); +} // note: as it known, there may leak some node -void func() -{ +void func() { std::unique_lock lk(cv_m); cv.wait(lk); pinpoint_add_clues(rootId, "xxxx", "bbbbbbss", E_LOC_CURRENT); @@ -45,26 +47,28 @@ void func() pinpoint_add_clue(rootId, "xxx", "bbbbbb", E_LOC_CURRENT); } -TEST(node, multipleThread) -{ +TEST(node, multipleThread) { // no crash, works fine NodeID root = pinpoint_start_trace(E_ROOT_NODE); std::vector threads; - for (int i = 0; i < 10; i++) { threads.push_back(std::thread(func)); } + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread(func)); + } sleep(2); cv.notify_all(); - for (int i = 0; i < 10; i++) { threads[i].join(); } + for (int i = 0; i < 10; i++) { + threads[i].join(); + } pinpoint_end_trace(root); pinpoint_end_trace(root); // EXPECT_TRUE(PoolManager::getInstance().NoNodeLeak()); } -TEST(node, wakeTrace) -{ +TEST(node, wakeTrace) { NodeID root = pinpoint_start_trace(E_ROOT_NODE); NodeID child1 = pinpoint_start_trace(root); @@ -74,6 +78,7 @@ TEST(node, wakeTrace) pinpoint_wake_trace(root); pinpoint_wake_trace(NodeID(159)); pinpoint_wake_trace(NodeID(1027)); + pinpoint_wake_trace(-1); // do something sleep(1); pinpoint_end_trace(child1); @@ -82,17 +87,15 @@ TEST(node, wakeTrace) // EXPECT_TRUE(PoolManager::getInstance().NoNodeLeak()); } -void test_opt(TraceNode &node, const char *opt, ...) -{ +void test_opt(TraceNode& node, const char* opt, ...) { va_list args; va_start(args, opt); node.setOpt(opt, &args); va_end(args); } -TEST(node, opt) -{ - TraceNode &node = PoolManager::getInstance().Take(); +TEST(node, opt) { + TraceNode& node = PoolManager::getInstance().Take(); test_opt(node, "TraceMinTimeMs:23", "TraceOnlyException", nullptr); @@ -112,10 +115,9 @@ TEST(node, opt) } static std::string span; -void capture(const char *msg) { span = msg; } +void capture(const char* msg) { span = msg; } //./bin/TestCommon --gtest_filter=node.pinpoint_start_traceV1 -TEST(node, pinpoint_start_traceV1) -{ +TEST(node, pinpoint_start_traceV1) { auto count = usedNode(); register_span_handler(capture); NodeID root, child1; @@ -124,7 +126,9 @@ TEST(node, pinpoint_start_traceV1) pinpoint_add_clue(child1, "name", "Take1sec", E_LOC_CURRENT); sleep(1); pinpoint_end_trace(child1); - + check_tracelimit(-1); + check_tracelimit(0); + check_tracelimit(time(nullptr)); child1 = pinpoint_start_traceV1(root, "TraceOnlyException", nullptr); pinpoint_add_clue(child1, "name", "Exception", E_LOC_CURRENT); pinpoint_add_exception(child1, "xxxxxxxxx"); @@ -168,8 +172,7 @@ TEST(node, pinpoint_start_traceV1) EXPECT_EQ(count, usedNode()); } -TEST(node, leak_node) -{ +TEST(node, leak_node) { auto count = PoolManager::getInstance().freeNodesCount(); NodeID root, child1, child2; root = pinpoint_start_trace(E_ROOT_NODE); @@ -185,9 +188,9 @@ TEST(node, leak_node) show_status(); } -TEST(node, tons_of_nodes_01) -{ - auto count = usedNode(); // PoolManager::getInstance().totoalNodesCount() - PoolManager::getInstance().freeNodesCount(); +TEST(node, tons_of_nodes_01) { + auto count = usedNode(); // PoolManager::getInstance().totoalNodesCount() - + // PoolManager::getInstance().freeNodesCount(); NodeID root = pinpoint_start_trace(E_ROOT_NODE); for (int i = 0; i < 1000; i++) { NodeID child1 = pinpoint_start_trace(root); @@ -195,7 +198,7 @@ TEST(node, tons_of_nodes_01) } pinpoint_end_trace(root); - EXPECT_EQ(count, usedNode()); //); + EXPECT_EQ(count, usedNode()); //); count = usedNode(); root = pinpoint_start_trace(E_ROOT_NODE); @@ -212,23 +215,24 @@ TEST(node, tons_of_nodes_01) EXPECT_EQ(count, usedNode()); } -TEST(node, tons_of_nodes_2k) -{ - auto count = usedNode(); // PoolManager::getInstance().totoalNodesCount() - PoolManager::getInstance().freeNodesCount(); +TEST(node, tons_of_nodes_2k) { + auto count = usedNode(); // PoolManager::getInstance().totoalNodesCount() - + // PoolManager::getInstance().freeNodesCount(); NodeID root = pinpoint_start_trace(E_ROOT_NODE); NodeID next = root; for (int i = 0; i < 2000; i++) { NodeID child = pinpoint_start_trace(next); pinpoint_end_trace(child); - if (i % 2 == 0) { next = child; } + if (i % 2 == 0) { + next = child; + } } pinpoint_end_trace(root); EXPECT_EQ(count, usedNode()); } -TEST(node, tons_of_nodes_leak) -{ +TEST(node, tons_of_nodes_leak) { auto count = usedNode(); NodeID root, child_1, child_2; @@ -244,8 +248,7 @@ TEST(node, tons_of_nodes_leak) EXPECT_EQ(count, usedNode()); } -TEST(node, tons_of_nodes_free_all) -{ +TEST(node, tons_of_nodes_free_all) { auto count = usedNode(); NodeID root, child_1, child_2; @@ -261,8 +264,7 @@ TEST(node, tons_of_nodes_free_all) EXPECT_EQ(count, usedNode()); } //./bin/TestCommon --gtest_filter=node.free_when_add -TEST(node, free_when_add) -{ +TEST(node, free_when_add) { auto count = usedNode(); NodeID root; auto make_it_busy = [&]() { @@ -287,8 +289,7 @@ TEST(node, free_when_add) } //./bin/TestCommon --gtest_filter=node.orphan_node -TEST(node, orphan_node) -{ +TEST(node, orphan_node) { auto count = usedNode(); NodeID root, child_1, orphan; root = pinpoint_start_trace(E_ROOT_NODE); @@ -307,8 +308,7 @@ TEST(node, orphan_node) EXPECT_EQ(count, usedNode()); } //./bin/TestCommon --gtest_filter=node.orphan_node_01 -TEST(node, orphan_node_01) -{ +TEST(node, orphan_node_01) { auto count = usedNode(); NodeID root, child_1, orphan; root = pinpoint_start_trace(E_ROOT_NODE); @@ -322,8 +322,7 @@ TEST(node, orphan_node_01) EXPECT_EQ(count, usedNode()); } //./bin/TestCommon --gtest_filter=node.orphan_root_parent_end -TEST(node, orphan_parent_root_end) -{ +TEST(node, orphan_parent_root_end) { auto count = usedNode(); NodeID root, child_1, orphan; root = pinpoint_start_trace(E_ROOT_NODE); @@ -337,8 +336,7 @@ TEST(node, orphan_parent_root_end) EXPECT_EQ(count, usedNode()); } -TEST(node, orphan_root_parent_end) -{ +TEST(node, orphan_root_parent_end) { auto count = usedNode(); NodeID root, child_1, orphan; root = pinpoint_start_trace(E_ROOT_NODE); @@ -352,12 +350,13 @@ TEST(node, orphan_root_parent_end) EXPECT_EQ(count, usedNode()); } // ./bin/TestCommon --gtest_filter=node.end_trace_in_mt -TEST(node, end_trace_in_mt) -{ +TEST(node, end_trace_in_mt) { auto count = usedNode(); NodeID root = pinpoint_start_trace(E_ROOT_NODE); NodeID next = root; - // limit size 100; due to https://github.com/pinpoint-apm/pinpoint-c-agent/runs/6806024797?check_suite_focus=true bus error under macos + // limit size 100; due to + // https://github.com/pinpoint-apm/pinpoint-c-agent/runs/6806024797?check_suite_focus=true bus + // error under macos for (int i = 0; i < 100; i++) { next = pinpoint_start_trace(next); pinpoint_end_trace(next); @@ -380,17 +379,19 @@ TEST(node, end_trace_in_mt) // wait for all threads running sleep(2); cv.notify_all(); - for (auto &thread : threads) thread.join(); + for (auto& thread : threads) + thread.join(); EXPECT_EQ(count, usedNode()); } // ./bin/TestCommon --gtest_filter=node.max_sub_nodes -TEST(node, max_sub_nodes) -{ +TEST(node, max_sub_nodes) { auto count = usedNode(); NodeID root = pinpoint_start_trace(E_ROOT_NODE); while (true) { NodeID next = pinpoint_start_trace(root); - if (next == E_INVALID_NODE) { break; } + if (next == E_INVALID_NODE) { + break; + } pinpoint_end_trace(next); } pinpoint_end_trace(root); diff --git a/plugins/PY/pinpointPy/CommonPlugin.py b/plugins/PY/pinpointPy/CommonPlugin.py index 0e84586b3..80ab12a62 100644 --- a/plugins/PY/pinpointPy/CommonPlugin.py +++ b/plugins/PY/pinpointPy/CommonPlugin.py @@ -21,12 +21,12 @@ class PinpointCommonPlugin(Common.PinTrace): def onBefore(self, parentId, *args, **kwargs): - parentId, args, kwargs = super().onBefore(*args, **kwargs) + trace_id, args, kwargs = super().onBefore(parentId, *args, **kwargs) pinpoint.add_trace_header( - Defines.PP_INTERCEPTOR_NAME, self.getUniqueName(), parentId) + Defines.PP_INTERCEPTOR_NAME, self.getUniqueName(), trace_id) pinpoint.add_trace_header( - Defines.PP_SERVER_TYPE, Defines.PP_METHOD_CALL, parentId) - return args, kwargs + Defines.PP_SERVER_TYPE, Defines.PP_METHOD_CALL, trace_id) + return trace_id, args, kwargs def onEnd(self, traceId, ret): # pinpoint.add_trace_header_v2(Defines.PP_RETURN, str(ret), traceId) diff --git a/plugins/PY/pinpointPy/Fastapi/test_fastapi.py b/plugins/PY/pinpointPy/Fastapi/test_fastapi.py index d36d5fb15..819b94da8 100644 --- a/plugins/PY/pinpointPy/Fastapi/test_fastapi.py +++ b/plugins/PY/pinpointPy/Fastapi/test_fastapi.py @@ -37,6 +37,7 @@ async def read_main(name, request: Request): def test_request_example(self): response = self.client.get("/cluster/abc") assert "ut" in response.headers + self.assertEqual(response.headers['ut'], "/cluster/{name}") if __name__ == '__main__': diff --git a/testapps/PY/app.py b/testapps/PY/app.py index d5b1e1895..a1287c45a 100644 --- a/testapps/PY/app.py +++ b/testapps/PY/app.py @@ -344,7 +344,7 @@ def test_mysql_form(): @app.route('/test_redis', methods=['GET']) def test_redis_form(): - r = RedisControl("localhost", "6379") + r = RedisControl("redis", "6379") r.connection() h1 = r.set("name", "Evy") r.delete("name") diff --git a/testapps/PY/templates/index.html b/testapps/PY/templates/index.html index af9129a27..3f81704f5 100644 --- a/testapps/PY/templates/index.html +++ b/testapps/PY/templates/index.html @@ -306,7 +306,7 @@

Error and exception

Call Remote

- remote url: + remote url:
diff --git a/testapps/backend.dockerfile b/testapps/backend.dockerfile index 47fba2405..d66ba25be 100644 --- a/testapps/backend.dockerfile +++ b/testapps/backend.dockerfile @@ -1,15 +1,16 @@ -FROM python:3.8 +FROM python:3.11 WORKDIR /app/ COPY testapps/backend/ /app/ -RUN pip install -r requirements.txt COPY setup.py /pinpoint-c-agent/setup.py COPY common/ /pinpoint-c-agent/common COPY README /pinpoint-c-agent/README COPY plugins/PY /pinpoint-c-agent/plugins/PY COPY src/PY /pinpoint-c-agent/src/PY + +RUN pip install -r requirements.txt RUN cd /pinpoint-c-agent && pip install -e . -# EXPOSE 8000 -CMD [ "uvicorn", "main:app","--host=0.0.0.0","--port=8000","--reload" ] \ No newline at end of file +EXPOSE 80 +CMD [ "python", "app.py" ] \ No newline at end of file diff --git a/testapps/backend/.gitignore b/testapps/backend/.gitignore new file mode 100644 index 000000000..8549d73f7 --- /dev/null +++ b/testapps/backend/.gitignore @@ -0,0 +1,9 @@ +composer.phar +vendor +.idea/ +Cache +__class_index_table +*.ast +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +composer.lock diff --git a/testapps/backend/DBControl.py b/testapps/backend/DBControl.py new file mode 100644 index 000000000..3491f87e4 --- /dev/null +++ b/testapps/backend/DBControl.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + + +import pymysql + + +class DBControl(object): + + def __init__(self, ip, user, pw, db=None): + self.ip = ip + self.user = user + self.pw = pw + self.db = db + self.conn = None + self.cursor = None + + def con_db(self): + if self.db is None: + self.conn = pymysql.connect(host=self.ip, user=self.user, passwd=self.pw) + else: + self.conn = pymysql.connect(host=self.ip,user=self.user,passwd=self.pw, db=self.db) + if self.conn is None: + print("Connect to Database failed!") + else: + self.cursor = self.conn.cursor() + + def db_select(self, sql): + self.cursor.execute(sql) + result = self.cursor.fetchall() + r = [] + for res in result: + r.append(res) + return r + + def db_close(self): + self.cursor.close() + self.conn.commit() + self.conn.close() diff --git a/testapps/backend/Readme-CN.md b/testapps/backend/Readme-CN.md new file mode 100644 index 000000000..c57a1712a --- /dev/null +++ b/testapps/backend/Readme-CN.md @@ -0,0 +1,32 @@ +# 将pinpoint集成到Flask中 + + +## 集成Pinpoint + +> 确保安装了pinpointPy模块。([如何安装pinpointPy模块](../../../DOC/PY/Readme-CN.md)) +1. 将```pinpoint``` 目录复制到您项目的根目录, 将 PinPointMiddleWare 添加到您的应用程序中。 + + ``` + app = Flask(__name__) + + from PinPointMiddleWare import PinPointMiddleWare + app.wsgi_app = PinPointMiddleWare(app,app.wsgi_app) + ...... + ``` +2. 将[插件](../plugins)复制到```pinpoint``` 目录。 ```plugin``` 里的插件是一些示例,您也可以根据这些例子编写您自己的插件。 + +3. Hook 您所关心的函数。 + + > Example: flask/test_recursion.py + Hook the function ```fact``` by add ```@PinpointCommonPlugin( __name__)``` just before it. + + + ``` + from pinpointPy.CommonPlugin import PinpointCommonPlugin + + + @PinpointCommonPlugin( __name__) + def fact(n): + ...... + ``` + diff --git a/testapps/backend/Readme.md b/testapps/backend/Readme.md new file mode 100644 index 000000000..106d2efa3 --- /dev/null +++ b/testapps/backend/Readme.md @@ -0,0 +1,32 @@ +# Integrating Pinpoint Into Flask + + +## Integrating pinpoint + +> Make sure pinpointPy module has been installed. ([How to Install pinpointPy module](../../../DOC/PY/Readme.md)) +1. Copy ```pinpoint``` directory to your project root. Add PinPointMiddleWare to your application. + + ``` + app = Flask(__name__) + + from PinPointMiddleWare import PinPointMiddleWare + app.wsgi_app = PinPointMiddleWare(app,app.wsgi_app) + ...... + ``` +2. Copy [plugins](../plugins) to the ```pinpoint``` directory . Plugins in ```plugin``` are some examples, you can also write your own plugin according to these examples. + +3. Hook the function you cared. + + > Example: flask/test_recursion.py + Hook the function ```fact``` by add ```@PinpointCommonPlugin('', __name__)``` just before it. + + + ``` + from pinpointPy.CommonPlugin import PinpointCommonPlugin + + + @PinpointCommonPlugin(__name__) + def fact(n): + ...... + ``` + diff --git a/testapps/backend/RedisControl.py b/testapps/backend/RedisControl.py new file mode 100644 index 000000000..d8d9c7dcd --- /dev/null +++ b/testapps/backend/RedisControl.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +import redis + + +class RedisControl(object): + + def __init__(self, host, port): + self.host = host + self.port = port + self.conn = None + + def connection(self): + self.conn = redis.Redis(host=self.host, port=self.port) + + def set(self, key, value): + self.conn.set(key, value) + return self.conn.get(key) + + def get(self, key): + return "%s:%s" % (key, self.conn.get(key)) + + def delete(self, key): + self.conn.delete(key) + return "Delete %s success!" diff --git a/testapps/backend/__init__.py b/testapps/backend/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/testapps/backend/app.py b/testapps/backend/app.py new file mode 100644 index 000000000..d2953a0fe --- /dev/null +++ b/testapps/backend/app.py @@ -0,0 +1,378 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# ------------------------------------------------------------------------------ +# Copyright 2020. NAVER Corp. +# +# 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. +# ------------------------------------------------------------------------------ +from RedisControl import RedisControl +from DBControl import DBControl +import test_returns +import test_args +from test_exception import UserDefineException +import test_exception +from test_static_class_method import Method +import test_abstract +import test_private +import test_special +import test_mixin +from test_band import BandClass +from flask import Flask, request, Response +from flask import render_template + +from datetime import datetime +import functools +import requests + +import test_function +from app1 import user_function +import person +import student +import teacher +import doctor +import test_recursion +import test_generatior +import test_higher_order +import test_return +import test_lambda +import test_decorator +import test_partial +import test_band +from pinpointPy.Flask.PinPointMiddleWare import PinPointMiddleWare +from pinpointPy import set_agent, monkey_patch_for_pinpoint, use_thread_local_context + +use_thread_local_context() +monkey_patch_for_pinpoint() + +app = Flask(__name__) + +set_agent("cd.dev.test.py.backend", "cd.dev.test.py.backend", 'tcp:dev-collector:10000', -1) + +app.wsgi_app = PinPointMiddleWare(app, app.wsgi_app) + + +@app.route('/', methods=['GET', 'POST']) +def home(): + return render_template("index.html") + + +GREETING = "Hello World!" + + +@app.route('/test_builtin_func/', methods=['GET']) +def builtin_form(arg): + data = abs(int(arg)) + return '''

%d Absolute Value is %d

''' % (int(arg), data) + + +@app.route('/test_package_func', methods=['GET']) +def date_form(): + dt = datetime.now() + return '''

Time: %s

''' % dt + + +@app.route('/test_user_func1', methods=['GET']) +def test_func1_form(): + func1 = test_function.test_func1("hello", "world") + return '''

%s

''' % func1 + + +@app.route('/test_ut/', methods=['GET']) +def test_ut(username): + + return f'{username}->{request.url_rule}\'s profile' + + +@app.route('/test_user_func2', methods=['GET']) +def test_func2_form(): + instance = test_function.TestUserFunc1("Evy", "99") + func2 = instance.test_func2() + return '''

%s

''' % func2 + + +@app.route('/test_user_func3', methods=['GET']) +def test_func3_form(): + func3 = user_function.test_func3("hello", "world") + return '''

%s

''' % func3 + + +@app.route('/test_user_func4', methods=['GET']) +def test_func4_form(): + instance = user_function.TestUserFunc2("Evy", "99") + func4 = instance.test_func4() + return '''

%s

''' % func4 + + +@app.route('/test_inherit_func', methods=['GET']) +def test_inherit_form(): + instance = student.Student() + s = instance.eat() + instance = teacher.Teacher() + t = instance.eat() + instance = doctor.Doctor() + d1 = instance.eat() + d2 = instance.other() + return '''

%s

+

%s

+

%s But %s

''' % (s, t, d1, d2) + + +@app.route('/test_recursion', methods=['GET']) +def test_recursion_form(): + print(request.url_rule) + r = test_recursion.fact(3) + return '''

%s

''' % r + + +@app.route('/test_generatior', methods=['GET']) +def test_generator_form(): + g1 = test_generatior.fib(6) + g2 = test_generatior.fib(6) + h1, h2 = "", "" + + for i in g1: + h1 = h1 + str(i) + " " + + while True: + try: + h2 = h2 + str(next(g2)) + " " + except StopIteration as e: + h2 = h2 + e.value + break + return '''

%s

+

%s

''' % (h1, h2) + + +@app.route('/test_higher_order', methods=['GET']) +def test_higher_order_form(): + from pinpointPy.CommonPlugin import PinpointCommonPlugin + + @PinpointCommonPlugin(__name__) + def f(x): + return x * x + + l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] + # r = map(f, l1) + r = map(test_higher_order.f, l1) + h = "[" + for i in r: + h = h + str(i) + "," + h = h + "]" + return '''

%s

''' % h + + +@app.route('/test_return_func', methods=['GET']) +def test_return_form(): + l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] + f = test_return.lazy_sum(*l1) + h = f() + return '''

%d

''' % h + + +@app.route('/test_lambda', methods=['GET']) +def test_lambda_form(): + def lambda_f(x): return x * x + h1 = lambda_f(3) + l = test_lambda.return_lambda(3) + h2 = l() + return '''

%d

+

%d

''' % (h1, h2) + + +@app.route('/test_decorator', methods=['GET']) +def test_decorator_form(): + h1 = test_decorator.func_in_decorator(3) + return '''

%d

''' % h1 + + +@app.route('/test_partial', methods=['GET']) +def test_partial_form(): + func2 = functools.partial(test_partial.func1, b="Evy") + h1 = func2("Hello ") + h2 = func2("Hello ", b="Mer") + return '''

%s

+

%s

''' % (h1, h2) + + +@app.route('/test_band', methods=['GET']) +def test_band_form(): + c1 = BandClass() + from types import MethodType + c1.band_func = MethodType(test_band.band_func, c1) + h1 = c1.band_func(3) + + BandClass.func = test_band.band_func + c2 = BandClass() + h2 = c2.func(6) + h3 = c1.func(9) + return '''

%s

+

%s

+

%s

''' % (h1, h2, h3) + + +@app.route('/test_mixin', methods=['GET']) +def test_mixin_form(): + i1 = test_mixin.Human() + h1 = i1.human_func() + h2 = i1.animal_func() + h3 = i1.think_func() + return '''

%s,%s,%s

''' % (h1, h2, h3) + + +@app.route('/test_special', methods=['GET']) +def test_special_form(): + i = test_special.Special("Evy", 99) + h1 = i.common_func() + return '''

%s

''' % h1 + + +@app.route('/test_private', methods=['GET']) +def test_private_form(): + i = test_private.Private() + h1 = i.common_func("Evy") + return '''

%s

''' % h1 + + +@app.route('/test_abstract', methods=['GET']) +def test_abstract_form(): + i = test_abstract.Txt() + h1 = i.read() + return '''

%s

''' % h1 + + +@app.route('/test_staticmethod', methods=['GET']) +def test_staticmethod_form(): + h1 = Method.static_method("Hello", "Static") + i1 = Method() + h2 = i1.static_method("Hello", "InstanceStatic") + return '''

%s

+

%s

''' % (h1, h2) + + +@app.route('/test_classmethod', methods=['GET']) +def test_classmethod_form(): + h1 = Method.class_method("Hello", "Class") + i1 = Method() + h2 = i1.class_method("Hello", "InstanceClass") + return '''

%s

+

%s

''' % (h1, h2) + + +@app.route('/test_exception', methods=['GET']) +def test_exception_form(): + h1 = test_exception.test_userexception("Evy") + return '''

%s

''' % h1 + + +@app.route('/test_uncaught_exception', methods=['GET']) +def test_uncaught_exception_form(): + h1 = test_exception.test_userexception("Evy") + return '''

%s

''' % h1 + + +@app.route('/test_caught_exception', methods=['GET']) +def test_caught_exception_form(): + h1, h2 = "test", "test" + try: + h1 = test_exception.test_userexception("Evy") + except UserDefineException as e: + h2 = e.value + return '''

%s

+

%s

''' % (h1, h2) + + +@app.route('/test_exception_in_recursion', methods=['GET']) +def test_exception_in_recursion_form(): + h1 = test_exception.test_exception_in_recursion(3) + return '''

%s

''' % h1 + + +@app.route('/test_arguments', methods=['GET']) +def test_arguments_form(): + i1 = Method() + f = open("app.py", 'r') + l1 = [None, 123, 3.1415, True, "abc", (123, "abc"), [456, "def"], {"a": 1, "b": 2}, set( + "abc"), i1, str(UserDefineException("Evy")), f, GREETING, lambda x: x*x] + l2 = [] + for i in l1: + l2.append(test_args.test_args1(i)) + f.close() + h1 = "
".join('%s' % str(id) for id in l2) + h2 = test_args.test_args2("Hello", "Evy", "a", "b", + "c", a="A", b="B", c="C") + return '''

%s

+

%s

''' % (h1, h2) + + +@app.route('/test_returns', methods=['GET']) +def test_returns_form(): + i1 = Method() + f = open("app.py", 'r') + l1 = [None, 123, 3.1415, True, "abc", (123, "abc"), [456, "def"], {"a": 1, "b": 2}, set( + "abc"), i1, str(UserDefineException("Evy")), f, GREETING, lambda x: x*x] + # l1 = [[456, "def"]] + l2 = [] + for i in l1: + l2.append(str(type(test_returns.test_returns1(i)))[8:-2]) + f.close() + h1 = "
".join('%s' % str(id) for id in l2) + h2 = test_returns.test_returns2( + "Hello", "Evy", "a", "b", "c", a="A", b="B", c="C") + return '''

%s

+

%s

''' % (h1, h2) + + +@app.route('/test_mysql', methods=['GET']) +def test_mysql_form(): + mysql = DBControl("dev-mysql", "root", "password", "employees") + mysql.con_db() + h1 = mysql.db_select("select * from employees limit 128") + mysql.db_close() + return "
".join('%s' % str(id) for id in h1) + + +@app.route('/test_redis', methods=['GET']) +def test_redis_form(): + r = RedisControl("redis", "6379") + r.connection() + h1 = r.set("name", "Evy") + r.delete("name") + return '''

%s

''' % h1 + + +@app.route('/call_remote', methods=['GET']) +def call_remote_form(): + remote = request.args['remote'] + h1 = requests.get(remote) + return h1.content + + +@app.route('/signin', methods=['GET']) +def signin_form(): + return '''
+

+

+

+
''' + + +@app.route('/signin', methods=['POST']) +def signin(): + if request.form['username'] == 'admin' and request.form['password'] == 'password': + return '

Hello, admin!

' + return '

Bad username or password.

' + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=80, processes=4, threaded=False) diff --git a/testapps/backend/app1/user_function.py b/testapps/backend/app1/user_function.py new file mode 100644 index 000000000..4d1a43f58 --- /dev/null +++ b/testapps/backend/app1/user_function.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin(__name__+".test_func3") +def test_func3(arg1, arg2): + return "this is test_func1: arg1=%s, arg2=%s"%(arg1, arg2) + +class TestUserFunc2(object): + + def __init__(self, name, score): + self.name = name + self.score = score + + @PinpointCommonPlugin(__name__+".TestUserFunc2.test_func4") + def test_func4(self): + return "%s\'s score is : %s"%(self.name, self.score) \ No newline at end of file diff --git a/testapps/backend/crud.py b/testapps/backend/crud.py deleted file mode 100644 index ade384c09..000000000 --- a/testapps/backend/crud.py +++ /dev/null @@ -1,36 +0,0 @@ -from sqlalchemy.orm import Session - -import models, schemas - - -def get_user(db: Session, user_id: int): - return db.query(models.User).filter(models.User.id == user_id).first() - - -def get_user_by_email(db: Session, email: str): - return db.query(models.User).filter(models.User.email == email).first() - - -def get_users(db: Session, skip: int = 0, limit: int = 100): - return db.query(models.User).offset(skip).limit(limit).all() - - -def create_user(db: Session, user: schemas.UserCreate): - fake_hashed_password = user.password + "notreallyhashed" - db_user = models.User(email=user.email, hashed_password=fake_hashed_password) - db.add(db_user) - db.commit() - db.refresh(db_user) - return db_user - - -def get_items(db: Session, skip: int = 0, limit: int = 100): - return db.query(models.Item).offset(skip).limit(limit).all() - - -def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int): - db_item = models.Item(**item.dict(), owner_id=user_id) - db.add(db_item) - db.commit() - db.refresh(db_item) - return db_item diff --git a/testapps/backend/database.py b/testapps/backend/database.py deleted file mode 100644 index b69b3bd44..000000000 --- a/testapps/backend/database.py +++ /dev/null @@ -1,13 +0,0 @@ -from sqlalchemy import create_engine -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker - -# SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" -SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:password@dev-mysql/employees?charset=utf8mb4" - -engine = create_engine( - SQLALCHEMY_DATABASE_URL -) -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - -Base = declarative_base() diff --git a/testapps/backend/doctor.py b/testapps/backend/doctor.py new file mode 100644 index 000000000..d328ea3e4 --- /dev/null +++ b/testapps/backend/doctor.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from person import Person +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Doctor(Person): + + @PinpointCommonPlugin(__name__+".Doctor.other") + def other(self): + return "Doctor not eating!" diff --git a/testapps/backend/main.py b/testapps/backend/main.py deleted file mode 100644 index e7ffa23aa..000000000 --- a/testapps/backend/main.py +++ /dev/null @@ -1,177 +0,0 @@ -from fastapi import FastAPI, Request, Response, Depends, HTTPException -from starlette.middleware import Middleware -from pinpointPy.Fastapi import PinPointMiddleWare, async_monkey_patch_for_pinpoint, use_starlette_context -from pinpointPy import set_agent, monkey_patch_for_pinpoint -from sqlalchemy.orm import Session -from starlette_context.middleware import ContextMiddleware -import aioredis -from contextlib import asynccontextmanager -import httpx -from typing import List - -import crud -import models -import schemas - -from database import SessionLocal, engine - -models.Base.metadata.create_all(bind=engine) - -redis = aioredis.from_url('redis://redis:6379', decode_responses=True) - - -class UserMiddleWare(PinPointMiddleWare): - async def dispatch(self, request: Request, call_next): - if request.url.path in ["/heartbeat", "/l7check"]: - return await call_next(request) - else: - return await super().dispatch(request, call_next) - - -middleware = [ - Middleware(ContextMiddleware), - Middleware(UserMiddleWare) -] - -use_starlette_context() -monkey_patch_for_pinpoint() -async_monkey_patch_for_pinpoint() - -set_agent("cd.dev.test.py.backends", "cd.dev.test.backends", 'tcp:dev-collector:10000') - - -@asynccontextmanager -async def lifespan(app: FastAPI): - app.requests_client = httpx.AsyncClient() - yield - await app.requests_client.aclose() - -app = FastAPI(title='FastAPI Pinpoint Example', - middleware=middleware, lifespan=lifespan) - - -def get_db(): - db = SessionLocal() - try: - yield db - finally: - db.close() - - -@app.middleware("http") -async def db_session_middleware(request: Request, call_next): - response = Response("Internal server error", status_code=500) - try: - request.state.db = SessionLocal() - response = await call_next(request) - finally: - request.state.db.close() - return response - - -@app.get("/") -async def root(): - return {"message": "Hello World"} - - -@app.get("/test-requests", tags=['sync-libraries']) -async def test_requests(request: Request, url='http://www.example.com'): - import requests - x = requests.get(url) - return {"response": x.status_code} - - -@app.get("/test-mysql-connector", tags=['sync-libraries']) -async def test_mysql_connector(request: Request): - import datetime - import mysql.connector - - cnx = mysql.connector.connect( - user='root', - password='password', - host='dev-mysql', - database='employees') - cursor = cnx.cursor() - - query = ("SELECT first_name, last_name, hire_date FROM employees " - "WHERE hire_date BETWEEN %s AND %s") - - hire_start = datetime.date(1999, 1, 1) - hire_end = datetime.date(1999, 12, 31) - - cursor.execute(query, (hire_start, hire_end)) - - for (first_name, last_name, hire_date) in cursor: - print("{}, {} was hired on {:%d %b %Y}".format( - last_name, first_name, hire_date)) - - cursor.close() - cnx.close() - return {"response": 200} - - -@app.get("/test-redis/set/{uid}", tags=["aioredis"]) -async def test_redis(uid: str = "default"): - await redis.set(uid, "50fdf310-7d3b-11ee-b962-0242ac120002", ex=1) - in_value = await redis.get(uid) - return {"uid": in_value} - - -@app.get("/httpx/example", tags=["httpx"]) -async def test_httpx(request: Request, url='http://www.example.com/'): - requests_client = request.app.requests_client - print(request.headers) - response = await requests_client.get(url) - return {"response": response.status_code} - - -@app.get("/httpx/backend", tags=["httpx"]) -async def test_httpx_backend(request: Request, url='http://backend:8000/'): - requests_client = request.app.requests_client - print(request.headers) - response = await requests_client.get(url) - return {"response": response.status_code} - - -@app.get("/httpx-self/", tags=["httpx"]) -async def test_httpx_self(request: Request): - requests_client = request.app.requests_client - response = await requests_client.get('http://127.0.0.1:8000/httpx/example') - return {"response": response.status_code} - -# thanks guide from https://fastapi.tiangolo.com/tutorial/sql-databases/ - - -@app.post("/users/", response_model=schemas.User, tags=["sqlalchemy"]) -def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): - db_user = crud.get_user_by_email(db, email=user.email) - if db_user: - raise HTTPException(status_code=400, detail="Email already registered") - return crud.create_user(db=db, user=user) - - -@app.get("/users/", response_model=List[schemas.User], tags=["sqlalchemy"]) -def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): - users = crud.get_users(db, skip=skip, limit=limit) - return users - - -@app.get("/users/{user_id}", response_model=schemas.User, tags=["sqlalchemy"]) -def read_user(user_id: int, db: Session = Depends(get_db)): - db_user = crud.get_user(db, user_id=user_id) - if db_user is None: - raise HTTPException(status_code=404, detail="User not found") - return db_user - - -@app.post("/users/{user_id}/items/", response_model=schemas.Item, tags=["sqlalchemy"]) -def create_item_for_user( - user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db) -): - return crud.create_user_item(db=db, item=item, user_id=user_id) - - -@app.get("/items/", response_model=List[schemas.Item], tags=["sqlalchemy"]) -def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): - items = crud.get_items(db, skip=skip, limit=limit) - return items diff --git a/testapps/backend/models.py b/testapps/backend/models.py deleted file mode 100644 index fd291a025..000000000 --- a/testapps/backend/models.py +++ /dev/null @@ -1,26 +0,0 @@ -from sqlalchemy import Boolean, Column, ForeignKey, Integer, String -from sqlalchemy.orm import relationship - -from database import Base - - -class User(Base): - __tablename__ = "users" - - id = Column(Integer, primary_key=True, index=True) - email = Column(String(20), unique=True, index=True) - hashed_password = Column(String(36)) - is_active = Column(Boolean, default=True) - - items = relationship("Item", back_populates="owner") - - -class Item(Base): - __tablename__ = "items" - - id = Column(Integer, primary_key=True, index=True) - title = Column(String(128), index=True) - description = Column(String(256), index=True) - owner_id = Column(Integer, ForeignKey("users.id")) - - owner = relationship("User", back_populates="items") diff --git a/testapps/backend/person.py b/testapps/backend/person.py new file mode 100644 index 000000000..0d4357fef --- /dev/null +++ b/testapps/backend/person.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Person(object): + @PinpointCommonPlugin(__name__+".Person.eat") + def eat(self): + return "father eating!" diff --git a/testapps/backend/requirements.txt b/testapps/backend/requirements.txt index c9c25a0ee..c8a1de8c9 100644 --- a/testapps/backend/requirements.txt +++ b/testapps/backend/requirements.txt @@ -1,11 +1,4 @@ -aioredis==2.0.1 -fastapi -httpx==0.25.1 -pydantic==2.4.2 -SQLAlchemy==2.0.23 -starlette -starlette_context -uvicorn -pymysql -requests -mysql-connector-python==8.0.31 \ No newline at end of file +Flask==3.0.0 +PyMySQL==1.1.0 +redis==5.0.1 +Requests==2.31.0 diff --git a/testapps/backend/schemas.py b/testapps/backend/schemas.py deleted file mode 100644 index c49beba88..000000000 --- a/testapps/backend/schemas.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import List, Union - -from pydantic import BaseModel - - -class ItemBase(BaseModel): - title: str - description: Union[str, None] = None - - -class ItemCreate(ItemBase): - pass - - -class Item(ItemBase): - id: int - owner_id: int - - class Config: - orm_mode = True - - -class UserBase(BaseModel): - email: str - - -class UserCreate(UserBase): - password: str - - -class User(UserBase): - id: int - is_active: bool - items: List[Item] = [] - - class Config: - orm_mode = True diff --git a/testapps/backend/server.py b/testapps/backend/server.py new file mode 100644 index 000000000..8903b279b --- /dev/null +++ b/testapps/backend/server.py @@ -0,0 +1,8 @@ +# server.py + +from wsgiref.simple_server import make_server +from test import application + +httpd = make_server('', 8001, application) +print('Serving HTTP on port 8000...') +httpd.serve_forever() \ No newline at end of file diff --git a/testapps/backend/student.py b/testapps/backend/student.py new file mode 100644 index 000000000..027824469 --- /dev/null +++ b/testapps/backend/student.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from person import Person +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Student(Person): + @PinpointCommonPlugin(__name__+".Student.eat") + def eat(self): + return "Student eating" diff --git a/testapps/backend/teacher.py b/testapps/backend/teacher.py new file mode 100644 index 000000000..95cb41300 --- /dev/null +++ b/testapps/backend/teacher.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from person import Person +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Teacher(Person): + + @PinpointCommonPlugin(__name__+".Teacher.eat") + def eat(self): + return super().eat()+"Teacher eating too!" diff --git a/testapps/backend/templates/index.html b/testapps/backend/templates/index.html new file mode 100644 index 000000000..3f81704f5 --- /dev/null +++ b/testapps/backend/templates/index.html @@ -0,0 +1,315 @@ + + + + + pinpoint-python demo + + +
+ +

Simple server

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DescriptionLink
+ Call user-defined function. + + click me +
+ Call user-defined function. + + click me +
+ Call user-defined function in a package. + + click me +
+ Call user-defined function in a package. + + click me +
+ Call inherit function + + click me +
+ Call Higher-order + + click me +
+ Call generator + + click me +
+ Call returned function. + + click me +
+ Call lambda function. + + click me +
+ Call decorator function. + + click me +
+ Call Partial function. + + click me +
+ Call band function to class. + + click me +
+ Call function in MixIn. + + click me +
+ Call special function. + + click me +
+ Call private function. + + click me +
+ Call abstract function + + click me +
+ Call Recursion + + click me +
+ Call Staticmethod function + + click me +
+ Call Classmethod function + + click me +
+ Call function with args + + click me +
+ Call function return datas + + click me +
+ Test Mysql + + click me +
+ Test Redis + + click me +
+ Test Uri Templated + + click me +
+
+ +

Error and exception

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LinkDescription
+ Test exception. + + click me +
+ Call uncaught exception + + click me +
+ Call caught exception + + click me +
+ Call exception in recursion + + click me +
+
+ +

Call Remote

+
+ remote url: + +
+ + + + diff --git a/testapps/backend/test.py b/testapps/backend/test.py new file mode 100644 index 000000000..12ccce43e --- /dev/null +++ b/testapps/backend/test.py @@ -0,0 +1,9 @@ +class Doctor: + def out(self): + print("out") + + +d = Doctor() +d.out() + + diff --git a/testapps/backend/test_abstract.py b/testapps/backend/test_abstract.py new file mode 100644 index 000000000..2ddca6268 --- /dev/null +++ b/testapps/backend/test_abstract.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + + +import abc +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class AllFle(metaclass=abc.ABCMeta): + all_type='file' + @PinpointCommonPlugin(__name__+'.AllFle.read') + @abc.abstractmethod + def read(self): + pass + + +class Txt(AllFle): + @PinpointCommonPlugin(__name__+'.Txt.read') + def read(self): + return "Reading txt!" diff --git a/testapps/backend/test_args.py b/testapps/backend/test_args.py new file mode 100644 index 000000000..31d8b9d56 --- /dev/null +++ b/testapps/backend/test_args.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin( __name__+".test_args1") +def test_args1(arg): + h = str(type(arg))[8:-2] + return h + + +@PinpointCommonPlugin(__name__+".test_args2") +def test_args2(a1, a2="Mer", *a3, **a4): + h = "Positional arg:" + a1 + "
Default arg:" + a2 + "
Variadic arg:" + "
Variadic arg:[" + ','.join(a3) + "]
Keyword arg:" + str(a4) + return h diff --git a/testapps/backend/test_band.py b/testapps/backend/test_band.py new file mode 100644 index 000000000..6812d6ffe --- /dev/null +++ b/testapps/backend/test_band.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin(__name__+".band_func") +def band_func(self, x): + self.x = x + return self.x * self.x + + +class BandClass(object): + pass diff --git a/testapps/backend/test_decorator.py b/testapps/backend/test_decorator.py new file mode 100644 index 000000000..352cd13e3 --- /dev/null +++ b/testapps/backend/test_decorator.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +import functools +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +def log(text): + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kw): + print('%s %s():' % (text, func.__name__)) + return func(*args, **kw) + return wrapper + return decorator + +@log('execute') +@PinpointCommonPlugin(__name__+".func_in_decorator") +def func_in_decorator(x): + return x * x \ No newline at end of file diff --git a/testapps/backend/test_exception.py b/testapps/backend/test_exception.py new file mode 100644 index 000000000..e37916202 --- /dev/null +++ b/testapps/backend/test_exception.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin(__name__+"test_nameerror") +def test_nameerror(arg): + xxx(arg, 123) + return "Call an undefined function." + +# def test_syntaxerror(arg) +# return "Test SyntaxError!" + + +@PinpointCommonPlugin( __name__+".test_ZeroDivisionError") +def test_ZeroDivisionError(arg): + return 3/arg + + +class UserDefineException(Exception): + + def __init__(self, user): + self.user = user + self.value = "UserDefineException:" + self.user + " raise an exception!" + + def __str__(self): + return self.value + + +@PinpointCommonPlugin(__name__+".test_userexception") +def test_userexception(arg): + if arg == "Evy": + raise UserDefineException(arg) + else: + return arg + + +@PinpointCommonPlugin(__name__+".test_exception_in_recursion") +def test_exception_in_recursion(n): + if n > 0: + return n/test_exception_in_recursion(n-1) + else: + return 0 diff --git a/testapps/backend/test_function.py b/testapps/backend/test_function.py new file mode 100644 index 000000000..acb0313f1 --- /dev/null +++ b/testapps/backend/test_function.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin(__name__+".test_func1") +def test_func1(arg1, arg2): + return "this is test_func1: arg1=%s, arg2=%s"%(arg1, arg2) + + +class TestUserFunc1(object): + + def __init__(self, name, score): + self.name = name + self.score = score + + @PinpointCommonPlugin(__name__+".TestUserFunc1.test_func2") + def test_func2(self): + return "%s\'s score is : %s"%(self.name, self.score) + + + diff --git a/testapps/backend/test_generatior.py b/testapps/backend/test_generatior.py new file mode 100644 index 000000000..fe5b00d2a --- /dev/null +++ b/testapps/backend/test_generatior.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + +@PinpointCommonPlugin( __name__+".fib") +def fib(max): + n, a, b = 0, 0, 1 + while n < max: + yield b + a, b = b, a + b + n = n + 1 + return 'done' + +# def fib(max): +# n, a, b = 0, 0, 1 +# while True: +# yield b +# a, b = b, a + b +# n = n + 1 +# if n > max: +# raise ValueError("") +# return 'done' diff --git a/testapps/backend/test_higher_order.py b/testapps/backend/test_higher_order.py new file mode 100644 index 000000000..d2281355c --- /dev/null +++ b/testapps/backend/test_higher_order.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin( __name__+".f") +def f(x:int): + return x * x diff --git a/testapps/backend/test_lambda.py b/testapps/backend/test_lambda.py new file mode 100644 index 000000000..c86645524 --- /dev/null +++ b/testapps/backend/test_lambda.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin(__name__+".in_lambda") +def in_lambda(b): + return b * b + + +@PinpointCommonPlugin( __name__+".return_lambda") +def return_lambda(a): + return lambda: in_lambda(a) + diff --git a/testapps/backend/test_mixin.py b/testapps/backend/test_mixin.py new file mode 100644 index 000000000..4dd52ef4f --- /dev/null +++ b/testapps/backend/test_mixin.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Animal(object): + @PinpointCommonPlugin(__name__+'.Animal.animal_func') + def animal_func(self): + return " and I am an animal" + + +class ThinkMixIn(object): + @PinpointCommonPlugin(__name__+'.ThinkMixIn.think_func') + def think_func(self): + return " and I can think" + + +class Human(Animal, ThinkMixIn): + @PinpointCommonPlugin( __name__+'.Human.human_func') + def human_func(self): + return "I am a human" \ No newline at end of file diff --git a/testapps/backend/test_partial.py b/testapps/backend/test_partial.py new file mode 100644 index 000000000..c2f5aa501 --- /dev/null +++ b/testapps/backend/test_partial.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin( __name__+".func1") +def func1(a, b="Wool"): + return a + b diff --git a/testapps/backend/test_private.py b/testapps/backend/test_private.py new file mode 100644 index 000000000..ec98b8692 --- /dev/null +++ b/testapps/backend/test_private.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Private(object): + @PinpointCommonPlugin(__name__+'.Private.__private_func') + def __private_func(self, arg): + return "Private called by " + arg + + @PinpointCommonPlugin(__name__+'.Private.common_func') + def common_func(self, name): + r = self.__private_func(name) + return r diff --git a/testapps/backend/test_recursion.py b/testapps/backend/test_recursion.py new file mode 100644 index 000000000..7ac3d1802 --- /dev/null +++ b/testapps/backend/test_recursion.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin(__name__+".fact") +def fact(n): + if n==1: + return 1 + return n * fact(n - 1) \ No newline at end of file diff --git a/testapps/backend/test_return.py b/testapps/backend/test_return.py new file mode 100644 index 000000000..d7b1d302f --- /dev/null +++ b/testapps/backend/test_return.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +def lazy_sum(*args): + @PinpointCommonPlugin(__name__+".sum") + def sum(): + ax = 0 + for n in args: + ax = ax + n + return ax + return sum diff --git a/testapps/backend/test_returns.py b/testapps/backend/test_returns.py new file mode 100644 index 000000000..1110227fd --- /dev/null +++ b/testapps/backend/test_returns.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +@PinpointCommonPlugin(__name__+".test_returns1") +def test_returns1(arg): + return arg + + +@PinpointCommonPlugin( __name__+".test_returns2") +def test_returns2(a1, a2="Mer", *a3, **a4): + a1 = a1 + " " + a2 = a2 + "!" + a3 = "[" + ",".join(a3) + "]" + a4 = str(a4) + return a1, a2, a3, a4 diff --git a/testapps/backend/test_special.py b/testapps/backend/test_special.py new file mode 100644 index 000000000..fefad326b --- /dev/null +++ b/testapps/backend/test_special.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Special(object): + @PinpointCommonPlugin(__name__+'.Special.__init__') + def __init__(self, name, age): + self.name = name + self.age = age + + @PinpointCommonPlugin(__name__+'.Special.common_func') + def common_func(self): + return "%s is %d years old." % (self.name, self.age) diff --git a/testapps/backend/test_static_class_method.py b/testapps/backend/test_static_class_method.py new file mode 100644 index 000000000..c3655568a --- /dev/null +++ b/testapps/backend/test_static_class_method.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from pinpointPy.CommonPlugin import PinpointCommonPlugin + + +class Method(object): + + @staticmethod + @PinpointCommonPlugin(__name__+'.Method.static_method') + def static_method(a, b): + return a + b + + @classmethod + @PinpointCommonPlugin(__name__+'.Method.class_method') + def class_method(cls, a, b): + return cls.__name__ + a + b diff --git a/testapps/compose.yaml b/testapps/compose.yaml index d82d23e04..1c990b019 100644 --- a/testapps/compose.yaml +++ b/testapps/compose.yaml @@ -90,7 +90,7 @@ services: dockerfile: testapps/backend.dockerfile context: ../ ports: - - 8187:8000 + - 8187:80 testapp-django: container_name: django diff --git a/testapps/fastapi/main.py b/testapps/fastapi/main.py index 107b1f941..fba5eb4a9 100644 --- a/testapps/fastapi/main.py +++ b/testapps/fastapi/main.py @@ -150,7 +150,7 @@ async def test_httpx(request: Request, url='http://www.example.com/'): @app.get("/httpx/backend", tags=["httpx"]) -async def test_httpx_backend(request: Request, url='http://backend:8000/'): +async def test_httpx_backend(request: Request, url='http://backend/'): requests_client = request.app.requests_client print(request.headers) response = await requests_client.get(url)