From 6e2564dc9ba13fa05d79fb095cd51b1817ab50a6 Mon Sep 17 00:00:00 2001 From: Vladimir Mihailenco Date: Sat, 10 Dec 2022 15:58:08 +0200 Subject: [PATCH] chore: add Otel and Uptrace example --- .gitignore | 2 +- example/opentelemetry/README.md | 45 +++ example/opentelemetry/composer.json | 19 ++ example/opentelemetry/config/alertmanager.yml | 53 ++++ .../opentelemetry/config/otel-collector.yaml | 68 +++++ example/opentelemetry/config/vector.toml | 39 +++ example/opentelemetry/docker-compose.yml | 81 ++++++ example/opentelemetry/image/metrics.png | Bin 0 -> 33371 bytes example/opentelemetry/image/relay-trace.png | Bin 0 -> 14977 bytes example/opentelemetry/main.php | 64 +++++ example/opentelemetry/uptrace.yml | 265 ++++++++++++++++++ 11 files changed, 635 insertions(+), 1 deletion(-) create mode 100644 example/opentelemetry/README.md create mode 100644 example/opentelemetry/composer.json create mode 100644 example/opentelemetry/config/alertmanager.yml create mode 100644 example/opentelemetry/config/otel-collector.yaml create mode 100644 example/opentelemetry/config/vector.toml create mode 100644 example/opentelemetry/docker-compose.yml create mode 100644 example/opentelemetry/image/metrics.png create mode 100644 example/opentelemetry/image/relay-trace.png create mode 100644 example/opentelemetry/main.php create mode 100644 example/opentelemetry/uptrace.yml diff --git a/.gitignore b/.gitignore index f74d1ab..7899570 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /stubs -/vendor +vendor composer.lock diff --git a/example/opentelemetry/README.md b/example/opentelemetry/README.md new file mode 100644 index 0000000..15d0149 --- /dev/null +++ b/example/opentelemetry/README.md @@ -0,0 +1,45 @@ +# Example for Relay OpenTelemetry instrumentation + +This example demonstrates how to monitor Redis using [OpenTelemetry](https://opentelemetry.io/) and +[Uptrace](https://uptrace.dev/get/open-source-apm.html. It requires Docker to start Redis Server and Uptrace. + +**Step 1**. Download the example using Git: + +```shell +git clone https://github.com/cachewerk/relay.git +cd example/opentelemetry +``` + +**Step 2**. Start the services using Docker: + +```shell +docker-compose up -d +``` + +**Step 3**. Make sure Redis and Uptrace are running: + +```shell +docker-compose logs redis +docker-compose logs uptrace +``` + +**Step 4**. Install dependencies and run the Relay example: + +```shell +composer install +php main.php +``` + +**Step 5**. Follow the link from the CLI to view the trace: + +```shell +php main.php +trace: http://localhost:14318/traces/ee029d8782242c8ed38b16d961093b35 +``` + +![Relay trace](./image/relay-trace.png) + +You can also open Uptrace UI at [http://localhost:14318](http://localhost:14318) to view available +spans, logs, and metrics. + +See [Monitoring Relay Redis client with OpenTelemetry](https://uptrace.dev/blog/posts/relay-cache-opentelemetry.html). diff --git a/example/opentelemetry/composer.json b/example/opentelemetry/composer.json new file mode 100644 index 0000000..daacfc8 --- /dev/null +++ b/example/opentelemetry/composer.json @@ -0,0 +1,19 @@ +{ + "name": "relay/example-opentelemetry", + "authors": [ + { + "name": "Vladimir Mihailenco", + "email": "vladimir.webdev@gmail.com" + } + ], + "require": { + "cachewerk/relay": "^0.5.1", + "uptrace/uptrace": "0.1.2" + }, + "autoload": { + "psr-4": { + "CacheWerk\\Relay\\": "../../src/" + } + }, + "minimum-stability": "dev" +} diff --git a/example/opentelemetry/config/alertmanager.yml b/example/opentelemetry/config/alertmanager.yml new file mode 100644 index 0000000..ac3e340 --- /dev/null +++ b/example/opentelemetry/config/alertmanager.yml @@ -0,0 +1,53 @@ +# See https://prometheus.io/docs/alerting/latest/configuration/ for details. + +global: + # The smarthost and SMTP sender used for mail notifications. + smtp_smarthost: "mailhog:1025" + smtp_from: "alertmanager@example.com" + smtp_require_tls: false + +receivers: + - name: "team-X" + email_configs: + - to: "some-receiver@example.com" + send_resolved: true + +# The root route on which each incoming alert enters. +route: + # The labels by which incoming alerts are grouped together. For example, + # multiple alerts coming in for cluster=A and alertname=LatencyHigh would + # be batched into a single group. + group_by: ["alertname", "cluster", "service"] + + # When a new group of alerts is created by an incoming alert, wait at + # least 'group_wait' to send the initial notification. + # This way ensures that you get multiple alerts for the same group that start + # firing shortly after another are batched together on the first + # notification. + group_wait: 30s + + # When the first notification was sent, wait 'group_interval' to send a batch + # of new alerts that started firing for that group. + group_interval: 5m + + # If an alert has successfully been sent, wait 'repeat_interval' to + # resend them. + repeat_interval: 3h + + # A default receiver + receiver: team-X + + # All the above attributes are inherited by all child routes and can + # overwritten on each. + + # The child route trees. + routes: + # This route matches error alerts created from spans or logs. + - matchers: + - alert_kind="error" + group_interval: 24h + receiver: team-X + +# The directory from which notification templates are read. +templates: + - "/etc/alertmanager/template/*.tmpl" diff --git a/example/opentelemetry/config/otel-collector.yaml b/example/opentelemetry/config/otel-collector.yaml new file mode 100644 index 0000000..b44dd1f --- /dev/null +++ b/example/opentelemetry/config/otel-collector.yaml @@ -0,0 +1,68 @@ +extensions: + health_check: + pprof: + endpoint: 0.0.0.0:1777 + zpages: + endpoint: 0.0.0.0:55679 + +receivers: + otlp: + protocols: + grpc: + http: + hostmetrics: + collection_interval: 10s + scrapers: + cpu: + disk: + load: + filesystem: + memory: + network: + paging: + redis: + endpoint: "redis-server:6379" + collection_interval: 10s + jaeger: + protocols: + grpc: + +processors: + resourcedetection: + detectors: ["system"] + batch: + send_batch_size: 10000 + timeout: 10s + +exporters: + logging: + logLevel: debug + otlp: + endpoint: uptrace:14317 + tls: + insecure: true + headers: { "uptrace-dsn": "http://project2_secret_token@localhost:14317/2" } + +service: + # telemetry: + # logs: + # level: DEBUG + pipelines: + traces: + receivers: [otlp, jaeger] + processors: [batch] + exporters: [otlp, logging] + metrics: + receivers: [otlp] + processors: [batch] + exporters: [otlp] + metrics/hostmetrics: + receivers: [hostmetrics, redis] + processors: [batch, resourcedetection] + exporters: [otlp] + logs: + receivers: [otlp] + processors: [batch] + exporters: [otlp] + + extensions: [health_check, pprof, zpages] diff --git a/example/opentelemetry/config/vector.toml b/example/opentelemetry/config/vector.toml new file mode 100644 index 0000000..10db91d --- /dev/null +++ b/example/opentelemetry/config/vector.toml @@ -0,0 +1,39 @@ +[sources.syslog_logs] +type = "demo_logs" +format = "syslog" +interval = 0.1 + +[sources.apache_common_logs] +type = "demo_logs" +format = "apache_common" +interval = 0.1 + +[sources.apache_error_logs] +type = "demo_logs" +format = "apache_error" +interval = 0.1 + +[sources.json_logs] +type = "demo_logs" +format = "json" +interval = 0.1 + +# Parse Syslog logs +# See the Vector Remap Language reference for more info: https://vrl.dev +[transforms.parse_logs] +type = "remap" +inputs = ["syslog_logs"] +source = ''' +. = parse_syslog!(string!(.message)) +''' + +# Export data to Uptrace. +[sinks.uptrace] +type = "http" +inputs = ["parse_logs", "apache_common_logs", "apache_error_logs", "json_logs"] +encoding.codec = "json" +framing.method = "newline_delimited" +compression = "gzip" +uri = "http://uptrace:14318/api/v1/vector/logs" +#uri = "https://api.uptrace.dev/api/v1/vector/logs" +headers.uptrace-dsn = "http://project2_secret_token@localhost:14317/2" diff --git a/example/opentelemetry/docker-compose.yml b/example/opentelemetry/docker-compose.yml new file mode 100644 index 0000000..4b47375 --- /dev/null +++ b/example/opentelemetry/docker-compose.yml @@ -0,0 +1,81 @@ +version: "3" + +services: + clickhouse: + image: clickhouse/clickhouse-server:22.10 + restart: on-failure + environment: + CLICKHOUSE_DB: uptrace + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"] + interval: 1s + timeout: 1s + retries: 30 + volumes: + - ch_data:/var/lib/clickhouse + ports: + - "8123:8123" + - "9000:9000" + + uptrace: + image: "uptrace/uptrace:1.2.4" + #image: "uptrace/uptrace-dev:latest" + restart: on-failure + volumes: + - uptrace_data:/var/lib/uptrace + - ./uptrace.yml:/etc/uptrace/uptrace.yml + #environment: + # - DEBUG=2 + ports: + - "14317:14317" + - "14318:14318" + depends_on: + clickhouse: + condition: service_healthy + + otel-collector: + image: otel/opentelemetry-collector-contrib:0.59.0 + restart: on-failure + volumes: + - ./config/otel-collector.yaml:/etc/otelcol-contrib/config.yaml + ports: + - "4317:4317" + - "4318:4318" + + redis-server: + image: redis + ports: + - "6379:6379" + redis-cli: + image: redis + + vector: + image: timberio/vector:0.24.X-alpine + volumes: + - ./config/vector.toml:/etc/vector/vector.toml:ro + + alertmanager: + image: prom/alertmanager:v0.24.0 + restart: on-failure + volumes: + - ./config/alertmanager.yml:/etc/alertmanager/config.yml + - alertmanager_data:/alertmanager + ports: + - 9093:9093 + command: + - "--config.file=/etc/alertmanager/config.yml" + - "--storage.path=/alertmanager" + + mailhog: + image: mailhog/mailhog:v1.0.1 + restart: on-failure + ports: + - "8025:8025" + +volumes: + uptrace_data: + driver: local + ch_data: + driver: local + alertmanager_data: + driver: local diff --git a/example/opentelemetry/image/metrics.png b/example/opentelemetry/image/metrics.png new file mode 100644 index 0000000000000000000000000000000000000000..3927aa0263f43c6f22d73f29f196fee96875b7d2 GIT binary patch literal 33371 zcmbrmcOYC__ctz8LXaXPYKjtJh~9|^qDK#-MGIyQ(K|^5iJsAWM6@vKIC=y@^fJsa zqeQQx_xc<6KKDNN`@G-hegF8`hqKSxd#}CrD*Mb?pEEu_S5u%Mqa!0BA)!!w_EeLE z$1@8% z{(+&zWtB;3ncaATqUv*};NIxW;nKR9xK7{M`MI^#rGs{}qbcOa-#6GvNbZm*K9$jS z$1SDc9rHx4lH70Q_Gj5Vdvbyl=f5u8vW@$gGWoSCPw4JvdhW#Am%X&o>S8X zg#b6D8TK`~%Xhe+O7iFh^602Z6&zPjC{K{R+reVIdNBveEtDy?oUGqJ1Fk38pF+At z$GT9EV`Yuf_B^oOYnI#ZD#_TZ7mnD16KZzm0kHq`WDsZX_M=Uc9?VgpygK<{7I0E# z>NRK$n`u}5Hhb1T?rVVEw(EzqcNlg+c8(SZ(&kxtISAvt%Lz8LU*j++19UV8MX|7I zWRQT~!lIS5NFhC2)WC{onTZgzOh$}pLGtc9C?!mucf7w_~xu1y(b8sCh$oc%M*Lm}JzH`7fLu@fmqJ`HyfP=Pv7|!) z28**_XJyU4;K>pDbtxa<+5fr}*MTj!@&Z7M5eDZk)>|Pz+wZjmB|gMLpAP6I@%kZ# z?`rmqd$iJ`%!<51!ev6Djc)+-vekOdijWWkOUNC|MdyChfQ)jt>L&NDr(uYJbfaOz z&~0p+gK#@x;fVbA-Z;o_&tu?~g$(#2n}egt9f}*_auqKpES}dRx2SeMV8vl>p{$~H zOw0Nnx|BUh>A^8L@RyIsLl^HDOoCoHUJGJH100xSw(mNhUnZPm-zb!S&H1Q9JQ4JP zIXWpX01_CdM5o{``N3}UkL_H-*Z>YxfZj|iEm9H}i&zih&M|XlC2iw7cA>P%9nzWiu9HmvPLqI1dh!pew{-s?j)YfdT zYwD|1IcV5&irO?mPg0H1UE}ZDjzSpRs@_ZsX&JtW`-vN* za^q4QATP70dPCWc=o&&q7d&uDzl`IN=fX9c)x$5B=Yfq9SgxS&6&@?Pc(L>_7z%j= zp8+8;ZZIdAd%lLR+JaOW;5>nw?S|gHLIc7#W`m%49~_oF?(aKJI7p|xPK}EmcPR$b z{6_kP^tOZ!dLg@Qyit9`4Nsyqbi=ez1t(Ss4`f|i_v z4%SJnSZipzRcYSXQ#{LMa7>8S`3fc(s>Z6@yGetv^;2&D23RX#Vk{uk3yQlS`-?DR z*i-R}r*8DG+_TG(<10#r-xk<~RF zw$-TETL#lxgistmk77OS9pN6#t))FoF|NSzXu|k4p<1e)b|uh*6Zdv0IS-4xsftsF z-0iHW8NP@6zK;|}YU|8nRfiC$0Xhm?j*qO`S(9ihgKoafN-qNBeY`>E_LnkbERT9Z zP<$-Et!(evdV>NJ-YW-Wqx0d<)$R9wfXM8Z8%?$8+rth4^_=dTdFPD|hFtV0=jDY@ zhKxk^=bz>A>n#+3;(CNwo8|8>+;lCVW!1x0ZpPmZYBq|Jf>-EQxIxO*1$VCsSDU(> zIy;AX@i#m*)oYh%e92exfjvb)d^DK^<#TpT!Nl?wLxkxWzz?teZiw?Ugyhcycb4Rj z;BkvlGVv#=PDO(hP_ad(FmxO+6(g4 z)KTNGa`yZS?ponkt3nmnnNhcQ2RYp&tA%B?vE6p$a_p%G&VRJO(3sW{ncZ;Y6DicOPm?NlS&K(psNyJl?~zY0!?(UoWtH4;3n#;YB&fP{8}3jqtAlYR%0W1N z=RUh4-)RLAJF;>9Lt~h%>zdWQJwYI5aG9K@T~3dDA@LJ4)=OUUfqCSo7k81^h477+ zoD5+wI;g(nrwmM*xsR({7C|vlYGJeXSpovu%{qeR`*EP}Rh4kp&j_!WeA{Kx0{6l$ zd6HW(_WaT0)Ks^YO35`H{2?#ICFAf#>F^!0SZ~QKrp%|BTI{(3K-83mK^euC*n)ht z#&l*6A@+=KTA4{2{u_sF=!f{NLIySFSGcUb?nuo6p?nv)y*rhUU(DuWgFH)Q%Rb)9 zDy>9rz8uL(!Zop2E(5oJ(;6H|0-Y-8>HAIl$@2)1j|{zCF|e(DV@A+}0vl9io3}Bv zmHZ97zKn#86sBN8JxdL47SS9>myMyf1(MdUO;L5K^4P%WX}EyhU7ir7l@U zXQ&e&fVS?Hz}$8dS+Kw>W&gTww3~rins&zh8C2b6EYVY`y=v=dj!|K7DJf=1PJ>$^uAI(uOd>g$XUAIn3#6tT zMBfC=k4wNI$&9i)xY*4|u;3|sa4?AXya(HI9lC>SU=9OWeRZI5ll%r~YcF3mBPuQioHb&T=AHWyJBhmqh(v0DK& z{M%z{sW$~r?ff>6(zg09P~RZ1NG8~ruSn*x%b&U2q;T_D)&0Gm4(SBrD>67Vb%b?$ zN66*3z9p^`pFYo(R&HVf!Uh!^z2nnCrL~&Tp3$h&tEZe!7i)b z#{U>hGGVEi5{o}#D%xC@dj50MAj)#g$2$iRasV_{5 z!l3mR?t3W^q`+0MC&EX1_Y8Ep1 z7^0YAmb5omHVT?5`?#>6ns0(joj(=FOp_SJMK2@xIVFCAG+ISr%9n$Y-)U(LY9P}Q zmO20}z9JQW>=2nh&t^(~WDakwTwlT%ek;!uU3#jvc6}i4nwo=cEhMPq`W~I6+a!<> zn!5!iN0)A*N5xR4oIUFNU^;cg;h}_X6}YQ^#a`HPG}1rDDXzEO_uex4aABgRX|8XP)iWIx zJu+|kO61q~^H%wtC8ZG`3*EQDD)Wzjc!E^@s4rQTl=(D$C+o%50%2kK$+Htu&j#Lw zQb+Umi^p^_nCGW0th3`Ge6ETz((ehD`^~x^=cx*%D=#dH>)?$5&llT^N%Y0aWcwWO zh|fEA?!IJro;syRQad_l-Jx^B=3XBs#p}MV2J)JE&V+c~$O-V}2Y0_i&cokAd^sqH zCxU;o?1}#y!pq_&9>ah)gxQxNCiawP@ZF6xek$kpFT?8z%o+#G$Ii5yHwNF~r87XA zC(hz?X)noTt`-H{xit9XuhV(>-AjXKp_k5rSI?h;UV8Tiaz5n}{+jseow?6dq2jbz zm&4AfC?JLzpI29z}VcQDc%eef5&v-MJ6_zKSyfYA@p6eU_c)3qvDSBhb8R_u;t@K#i zqV&f3q}1-L@<~3rIclL)Q#3z*(~9!F!yZFbDDB{8jZm!%c*9_pfsXBu3yp}kdjfX{ zBuWER)nB2Z@Lr);ybe@Jso1O^+xcffc95g!0!UO3Q4{dHrsQX!r@usv{h%T0=#QqO z$C}r;{L88@^6tsei@-*QKd`wm+o7|I!z?cMddc^`hN4*-ol5p}Oqpktr))Cl3yjES z<}ZqUb6@hH2QAPq9`V~Z3E@|p%20Tp#<6D1FA+;%|8>&$H%Px%I!DNt&5oIzA7}0QSr^PQ$x54Ye+hzHU8-la zO(pFp?fWk7J<24~8|5!|4n>`B^}X#;Th^bPkYAw2zxt_LAF(zsu{(V)&6J%sU)UR> z==Ukl5mLQ)hh1eY#sAZ~vwNtM%>HOmkb8U~5cRcCEZS>BnMNeF0b?z~IY{&B6(RO! z=}qycM$dYh(~uhH9td6d1kugORz`I7FUc1?i{MS^aNG<|9;a5;B(VF|V>;b1%4P=p zmj;$PUuw0BB8TrfmFW2B4aJsbzd+a)O?OYXb`H&biD&Ospgi=*3{d$ngh<#^nYg7u zS<0>b(=?uMe+*4>YwmsQwJ)6lA`g8N+U`6G8&wWo*4^<e!rzX>YkCB<&6 zE~*|%m9*cf+O%ub6f75m+unwCzSGV(t?n=HoS6+yxd62_LYON*x@?Sz4zRj^(M`7o z*}LuHayC!-YM|PAo9XZaxdeQo1iRKMVgl&Tt*-Jk%}*+JQJ+qFrP(~3Pq!ao9OLN} zxl}mOzFb^eZkEHgjZnK{AD87S1_&Su67aT&=VTo?W-&od=5ON9aBdTTrW-OwpUjQU zh(c44=j~&px>H5JW8^2rgGk-bVqmfQ;mgQ$3lUJ&L|+kPMfBXt;NA+^suCNshZovw zrbv3ILJhKv5C{nh-wT=$u|nD+TvK@AIz)A11ydv~s^q(Yh@R!96Dq1LHZwxBS=dP8 z9YTaL57_!XT89AXjRQ*^wzo|yEy5Bw9(;2%LeP}NRw76D7RK?#6R1y_kJ_#qG;fe zHz*V+m?`^uSrwjSuy6I&vmQj+YrUIf?@F&uCB<7Qep3-p2{lffQ--$-QPjOfM)7qp z`eI23rMk)^kO$WAF(wxNv&R?UM&GDbI~NCM@(1_#g_g~f73+Rte8K>&_P8RQSJ5N& zz=fls&FY^G}l~v`^O0d``+1}Umx&Kr%{y02yD!X{PDQVV!s(*xc z=w0-7k*ab-zf?Mq_30*FKs~OrEwwWR7F6UlNDN*!5b%M*_uf85xe^Ulw*qXH#(GEy z*B9}Z52RQST^7v$S-8g8m{9{aKM)x^?|%m*$mTMY1U<`jo&Z8HwxLj7jzQL zU*oczZ)XIX*o=7n63UF@%XtpQD#yzKnDLnUHRZ$CSJDO^<7c{h@&rshU_JLGQ@&VuE{t zsmE`4vCI0cy4dtf-FP;O+sbJSOI-l-6bx@+U3|1kpjk0NJZz^P2zI4~7Jrd)9k;T2 zsGD~Qw>w@H00^o+z(WwOWLgEkm>3E!j@c@H%S|L*^X<|h`+$`sx=So7-TP=)tk)V_9}DU{a5?lWm-JSSvc(7N&PCi#(wmzyt#1Otl~=C*U+D1 zTXZN9DP+W&^4j+=IV-tSqgYeoQU2z+oc&yM59?)N$Azt zX8SH|cgwt0N3%JLjx6f3WK6ukMUX)B? zgYZ8&DUT)1nG3bSS!6v~2Had+Mz8GG1e>hJeF^uz4V?K`>80uUtHe@AX`wFsUF4vT z|1K!jCTnsZTk-lkw;aXn)Ou|7!zr@c%JnybWhi8@l^hKPJN_@BX5l z1Tgzso6%)dq`Qhi3A#e9FngvftXUVB6%Yt_5se0MVkk!9$6qF(bL!lpW04XcjMQA%KG2t7I8c?&N5pfI!dji0)AN`Rn zXc~F!|3d{8ksvd3VIfbD&Gz)xWG!N*ZgbaN-r#-2PJ|vR;9A*Hlm~3jsU0uOvE4rU zTV(RcqM2@Y-xm46-4A?UD4rCD)!Uo$s=l(q%riS~!U4)bD-uCnp*iu`wwFR1$G+If z#rq+v$J;;C@aO$FrfTIleib}1Cn~BgVWKLatY&z1-{|LYjc}ycUYu3`kYypF{IGPz z2ex>=(%_^RBD??e^2shwCU@pRRaM%BDNC*pf6)5iKCZ#d1Mv3YJb{QO(Z@lEPn4`$F3^UKT@T-|2Kuqa4?zwwUsXgiOrgls0CXMYBcA2`13WFg?pm+9r)M0H!xgLZ<@t)Hu9= zQ?nM21vkHZ0DC@x)5EdG)V(xfy}J8qS5i-_o>lgXDdc}pt2~u#7sWrFQr#=Ao%%7+ z>i^-HfBPCRH2jC>iS@ezqu!%s;_shYlj{w*5TIo?=5UA^fI?MyyYWDPNALvOHMch($Dvp6Qg& zqOI52>*>TyhlDB~*;1<=@nx196+npsJcpAQ87==*>*VM--~G=JLmhk;)t$`RtW2Vc zQ&C|L=N@B?tjQ&9luu8LHqb60V>n9hnoJK(K>-0XIXWdExttDhb{KPAbm;DxWWqgR zS637~TIw8p3;t*fdjq~XHK{fEUu6vA>eULfGv0YZ6m!wGx^~Jk1*=N``q_K%wGL1o zS2JZpr@Ap?O^(I7dMz1Fg%L;hM1k@{ikv8-7M|e`SvVDlL#0qgp2x+pQm3o#0X(YK$8v|{AB8uKvXFB+6PEt z+R19=r0hOr1I|0x2cwAe9)GZN@op6VsT^^j4fP*^EF^Zirdn&FI{Y2g1S#I1!8OR0 zjnsy=5^b6uascAn<4*^)YiY((PLX0kpD*%WsOfR}itk|O4Z%`!IwG5bLSW;m>Z&$^ z=tMoP)h(}LwogOii2_dkrt{}|ol^tE)FDew8Tk`EPe@7O-a}%ChJi95HOIlz$NoH# z3wJ)Dz{5$Q@I28<)_5rmey4MnfOK*|{qenjZJnnZCsB8Q?w-WT>G9{b`e*&LsUi!6 z9+;L=p%BCszdfyEJSHW4i4I|mNBTV4tM<5kgQ&@G0Df{5W6AazviSv>srT+$nPj#1 z+o!VDu=xtuQ$U@^tS!aNBtRTIv=iJeP319*~_fb!{16 zK=8jk?Mm^!{tYe*j^?bts;<~OIm*+Ak@sZ%JuW}@6z^y!o~@PstCG0hty50c<*tv3 z+XJ~C2DBNK2&?=+tP{;t>0MkM`IZ1`I+nXbW!E_`RJq(XzbM`Syq(LUt&I=}b zIlt!JMUT2D?$p9Ylc}jbLqr)(@HUAGh9Bz;ppN_GsFY`GuW<;pNgm|zWL0JThv>g7 z7~qQ%%wqhN$1wRySH$G-h2$D_}%Qunaym}7Wddep?_|T()FppCtbY^$;oalzZaYqnr#Rj)RtGL&D&NQWGikM zlWvhlO9o6%nMy`eBJRmE!@&S(Oq5om>htyA&!4O1mb|m*NBYyH1}_

@WiK8sy#u~AmzNkXUf>EdgW+|P*? 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 literal 0 HcmV?d00001 diff --git a/example/opentelemetry/image/relay-trace.png b/example/opentelemetry/image/relay-trace.png new file mode 100644 index 0000000000000000000000000000000000000000..704eb0c8d776b642cde5a576cafd5f0470f9d4ea GIT binary patch literal 14977 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 jM;f5V|Gt8_ylLj60setDsn('http://project2_secret_token@localhost:14318/2'); +$conf->setServiceName('myservice'); +$conf->setServiceVersion('1.0.0'); + +$uptrace = new Uptrace\Distro($conf); +$tracerProvider = $uptrace->createTracerProvider(); +$tracer = $tracerProvider->getTracer('relay/example-opentelemetry'); + +$redis = new RelayOpenTelemetry(function() { + return new Relay\Relay; +}, $tracerProvider); + +$redis->connect('127.0.0.1', 6379); + +$span = handleRequest($tracer, $redis); +echo $uptrace->traceUrl($span) . PHP_EOL; + +for ($i = 0; $i <= 1000000; $i++) { + handleRequest($tracer, $redis); + sleep(1); +} + +// Send buffered spans and free resources. +$tracerProvider->shutdown(); + +function handleRequest($tracer, $redis) { + $span = $tracer->spanBuilder('handle-request')->startSpan(); + $spanScope = $span->activate(); + + $value = $redis->get('count'); + $redis->set('counter', (int)$value + 1); + + $redis->multi() + ->set('key1', 'val1') + ->get('key1') + ->set('key2', 'val2') + ->get('key2') + ->exec(); + + $pipe = $redis->pipeline(); + for ($i = 0; $i <= 100; $i++) { + $pipe->set('key' . $i, ''); + } + $pipe->exec(); + + $it = NULL; + do { + // Scan for some keys + $arr_keys = $redis->scan($it); + } while ($it > 0); + + $spanScope->detach(); + $span->end(); + + return $span; +} diff --git a/example/opentelemetry/uptrace.yml b/example/opentelemetry/uptrace.yml new file mode 100644 index 0000000..33d393a --- /dev/null +++ b/example/opentelemetry/uptrace.yml @@ -0,0 +1,265 @@ +## +## Uptrace configuration file. +## See https://uptrace.dev/get/config.html for details. +## +## You can use environment variables anywhere in this file, for example: +## +## foo: $FOO +## bar: ${BAR} +## baz: ${BAZ:default} +## +## To escape `$`, use `$$`, for example: +## +## foo: $$FOO_BAR +## + +## +## ClickHouse database credentials. +## +ch: + # Connection string for a ClickHouse database. For example: + # clickhouse://:@:/?sslmode=disable + # + # See https://clickhouse.uptrace.dev/guide/golang-clickhouse.html#options + dsn: "clickhouse://default:@clickhouse:9000/uptrace?sslmode=disable" + + # Maximum query execution time. + max_execution_time: 30s + +## +## A list of pre-configured projects. Each project is fully isolated. +## +projects: + # Conventionally, the first project is used to monitor Uptrace itself. + - id: 1 + name: Uptrace + # Token grants write access to the project. Keep a secret. + token: project1_secret_token + pinned_attrs: + - service + - host.name + - deployment.environment + # Group spans by deployment.environment attribute. + group_by_env: false + # Group funcs spans by service.name attribute. + group_funcs_by_service: false + + # Other projects can be used to monitor your applications. + # To monitor micro-services or multiple related services, use a single project. + - id: 2 + name: My project + token: project2_secret_token + pinned_attrs: + - service + - host.name + - deployment.environment + # Group spans by deployment.environment attribute. + group_by_env: false + # Group funcs spans by service.name attribute. + group_funcs_by_service: false + +## +## Create metrics from spans and events. +## +metrics_from_spans: + - name: uptrace.tracing.spans + description: Total number of spans including logs and events + instrument: counter + unit: 1 + value: span.count + attrs: [span.system, service.name, host.name, span.status_code] + + - name: uptrace.tracing.spans_duration + description: Spans duration + instrument: histogram + unit: microseconds + value: span.duration / 1000 + attrs: [span.system, service.name, host.name] + where: span.duration > 0 + + - name: uptrace.tracing.error_rate + description: Spans error rate + instrument: gauge + unit: percents + value: span.error_count / span.count + attrs: [span.system, service.name, host.name] + +## +## Alerting rules for monitoring metrics. +## +## See https://uptrace.dev/get/alerting.html for details. +## +alerting: + rules: + - name: Redis is working + metrics: + - uptrace.tracing.spans as $spans + query: + - $spans > 0 + - where system = 'db:redis' + for: 5m + annotations: + summary: "Got {{ $values.spans }} spans from Redis" + + - name: Redis is failing + metrics: + - uptrace.tracing.spans as $spans + query: + - $spans{status='error'} > 10 + - where system = 'db:redis' + for: 5m + + # Create alerts from error logs and span events. + create_alerts_from_spans: + enabled: true + labels: + alert_kind: error + +## +## To require authentication, uncomment one of the following sections. +## +auth: + # users: + # - username: uptrace + # password: uptrace + # - username: admin + # password: admin + + # Cloudflare Zero Trust Access (Identity) + # See https://developers.cloudflare.com/cloudflare-one/identity/ for more info. + # cloudflare: + # # The base URL of the Cloudflare Zero Trust team. + # - team_url: https://myteam.cloudflareaccess.com + # # The Application Audience (AUD) Tag for this application. + # # You can retrieve this from the Cloudflare Zero Trust 'Access' Dashboard. + # audience: bea6df23b944e4a0cd178609ba1bb64dc98dfe1f66ae7b918e563f6cf28b37e0 + + # OpenID Connect (Single Sign-On) + # oidc: + # # The ID is used in API endpoints, for example, in redirect URL + # # `http:///api/v1/sso//callback`. + # - id: keycloak + # # Display name for the button in the login form. + # # Default to 'OpenID Connect' + # display_name: Keycloak + # # The base URL for the OIDC provider. + # issuer_url: http://localhost:8080/realms/uptrace + # # The OAuth 2.0 Client ID + # client_id: uptrace + # # The OAuth 2.0 Client Secret + # client_secret: ogbhd8Q0X0e5AZFGSG3m9oirPvnetqkA + # # Additional OAuth 2.0 scopes to request from the OIDC provider. + # # Defaults to 'profile'. 'openid' is requested by default and need not be specified. + # scopes: + # - profile + # # The OIDC UserInfo claim to use as the user's username. + # # Defaults to 'preferred_username'. + # claim: preferred_username + +## +## AlertManager client configuration. +## See https://uptrace.dev/get/alerting.html for details. +## +## Note that this is NOT an AlertManager config and you need to configure AlertManager separately. +## See https://prometheus.io/docs/alerting/latest/configuration/ for details. +## +alertmanager_client: + # AlertManager API endpoints that Uptrace uses to manage alerts. + urls: + - "http://localhost:9093/api/v2/alerts" + +## +## Various options to tweak ClickHouse schema. +## For changes to take effect, you need reset the ClickHouse database with `ch reset`. +## +ch_schema: + # Compression codec, for example, LZ4, ZSTD(3), or Default. + compression: ZSTD(3) + + # Whether to use ReplicatedMergeTree instead of MergeTree. + replicated: false + + # Cluster name for Distributed tables and ON CLUSTER clause. + #cluster: uptrace1 + + spans: + storage_policy: "default" + # Delete spans data after 30 days. + ttl_delete: 30 DAY + + metrics: + storage_policy: "default" + # Delete metrics data after 90 days. + ttl_delete: 90 DAY + +## +## Addresses on which Uptrace receives gRPC and HTTP requests. +## +listen: + # OTLP/gRPC API. + grpc: + addr: ":14317" + # tls: + # cert_file: config/tls/uptrace.crt + # key_file: config/tls/uptrace.key + + # OTLP/HTTP API and Uptrace API with UI. + http: + addr: ":14318" + # tls: + # cert_file: config/tls/uptrace.crt + # key_file: config/tls/uptrace.key + +## +## Various options for Uptrace UI. +## +site: + # Overrides public URL for Vue-powered UI in case you put Uptrace behind a proxy. + #addr: 'https://uptrace.mydomain.com' + +## +## Spans processing options. +## +spans: + # The size of the Go chan used to buffer incoming spans. + # If the buffer is full, Uptrace starts to drop spans. + #buffer_size: 100000 + + # The number of spans to insert in a single query. + #batch_size: 10000 + +## +## Metrics processing options. +## +metrics: + # List of attributes to drop for being noisy. + drop_attrs: + - telemetry.sdk.language + - telemetry.sdk.name + - telemetry.sdk.version + + # The size of the Go chan used to buffer incoming measures. + # If the buffer is full, Uptrace starts to drop measures. + #buffer_size: 100000 + + # The number of measures to insert in a single query. + #batch_size: 10000 + +## +## SQLite/PostgreSQL db that is used to store metadata such us metric names, dashboards, alerts, +## and so on. +## +db: + # Either sqlite or postgres. + driver: sqlite + # Database connection string. + # + # Uptrace automatically creates SQLite database file in the current working directory. + # Make sure the directory is writable by Uptrace process. + dsn: "file:uptrace.sqlite3?_pragma=foreign_keys(1)&_pragma=busy_timeout(1000)" + +# Secret key that is used to sign JWT tokens etc. +secret_key: 102c1a557c314fc28198acd017960843 + +# Enable to log HTTP requests and database queries. +debug: false