Skip to content

Commit

Permalink
πŸ§‘β€πŸ’» feat(like-service): Add Jaeger support
Browse files Browse the repository at this point in the history
  • Loading branch information
eliasgierlinger authored and W3D3 committed Nov 20, 2023
1 parent 53f4c69 commit dba5dc5
Show file tree
Hide file tree
Showing 15 changed files with 1,458 additions and 687 deletions.
26 changes: 26 additions & 0 deletions chart/jaeger-otlp-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2023 Dynatrace LLC
#
# 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.

# This enables OpenTelemetry ingress for Jaeger when applied using --values with helm install
collector:
service:
otlp:
http:
port: 4318
name: otlp-http
nodePort: 4318
grpc:
port: 4317
name: otlp-grpc
nodePort: 4317
2 changes: 2 additions & 0 deletions chart/templates/frontend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ spec:
value: {{ quote .Values.frontend.deployment.container.env.MEMBERSHIP_SERVICE_ADDRESS }}
- name: PROFILE_SERVICE_ADDRESS
value: {{ quote .Values.frontend.deployment.container.env.PROFILE_SERVICE_ADDRESS }}
- name: LIKE_SERVICE_ADDRES
value: {{ quote .Values.frontend.deployment.container.env.LIKE_SERVICE_ADDRES }}
- name: FRONTEND_BASE_PATH
value: {{ quote .Values.frontend.deployment.container.env.FRONTEND_BASE_PATH }}
- name: AD_SERVICE_BASE_PATH
Expand Down
8 changes: 4 additions & 4 deletions chart/templates/like-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ spec:
{{if .Values.tracing.enabled}}
- name: JAEGER_AGENT_HOST
value: {{ quote (printf "%s-%s" .Values.jaeger.name .Values.likeService.deployment.container.env.JAEGER_AGENT_HOST) }}
- name: JAEGER_SAMPLER_TYPE
value: {{ quote .Values.likeService.deployment.container.env.JAEGER_SAMPLER_TYPE }}
- name: JAEGER_SAMPLER_PARAM
value: {{ quote .Values.likeService.deployment.container.env.JAEGER_SAMPLER_PARAM }}
- name: JAEGER_PORT
value: {{ quote .Values.likeService.deployment.container.env.JAEGER_PORT }}
- name: SERVICE_NAME
value: {{ quote .Values.likeService.deployment.container.env.SERVICE_NAME }}
- name: JAEGER_DISABLED
value: {{ quote .Values.likeService.deployment.container.env.JAEGER_DISABLED }}
{{end}}
6 changes: 6 additions & 0 deletions chart/tracing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ frontend:
JAEGER_SAMPLER_PARAM: 1
JAEGER_DISABLED: false

likeService:
deployment:
container:
env:
JAEGER_DISABLED: false

microblogService:
deployment:
container:
Expand Down
6 changes: 3 additions & 3 deletions chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -404,10 +404,10 @@ likeService:
ports:
containerPort: 8000
env:
JAEGER_AGENT_HOST: agent # change depending on your jaeger deployment
JAEGER_SAMPLER_TYPE: const
JAEGER_SAMPLER_PARAM: 0
JAEGER_AGENT_HOST: collector # PHP OpenTelemetry sends data to jaeger-collector instead of jaeger-agent
JAEGER_DISABLED: true
JAEGER_PORT: 4318
SERVICE_NAME: unguard-like-service
SERVER_PORT: 8000
API_PATH: /like-service
USER_AUTH_SERVICE_ADDRESS: unguard-user-auth-service
Expand Down
6 changes: 5 additions & 1 deletion docs/TRACING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ This document explains how to install Jaeger tracing using Helm to the cluster.
## Install Jaeger

1. For local development
1. Install the Jaeger-Operator
1. Install Jaeger (takes a couple of minutes)
```sh
helm install jaeger jaegertracing/jaeger --version 0.71.14 --wait --namespace unguard --create-namespace --values ./chart/jaeger-otlp-values.yaml
```
2. Install the Jaeger-Operator
```sh
helm install jaeger-operator jaegertracing/jaeger-operator --version 2.22.0 --wait --namespace unguard --create-namespace
```
Expand Down
4 changes: 2 additions & 2 deletions src/frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ frontendLogger.info("FRONTEND_BASE_PATH is set to " + process.env.FRONTEND_BASE_
frontendLogger.info("AD_SERVICE_BASE_PATH is set to " + process.env.AD_SERVICE_BASE_PATH);
frontendLogger.info("STATUS_SERVICE_BASE_PATH is set to " + process.env.STATUS_SERVICE_BASE_PATH);
frontendLogger.info("PROFILE_SERVICE_ADDRESS is set to " + process.env.PROFILE_SERVICE_ADDRESS);
frontendLogger.info("LIKE_SERVICE_ADDRESS is set to " + process.env.UNGUARD_LIKE_SERVICE_SERVICE_HOST + ":" + process.env.UNGUARD_LIKE_SERVICE_SERVICE_PORT); //TODO: find out why LIKE_SERVICE_ADDRESS does not work
frontendLogger.info("LIKE_SERVICE_ADDRESS is set to " + process.env.LIKE_SERVICE_ADDRES);

let app = express();

Expand Down Expand Up @@ -144,7 +144,7 @@ app.use((req, res, next) => {
const MEMBERSHIP_SERVICE_API = createAxiosInstance(req, "http://" + process.env.MEMBERSHIP_SERVICE_ADDRESS + process.env.MEMBERSHIP_SERVICE_BASE_PATH, membershipServiceApiLogger, cookieHeader)
const PROFILE_SERVICE_API = createAxiosInstance(req, "http://" + process.env.PROFILE_SERVICE_ADDRESS, profileServiceLogger);
const STATUS_SERVICE_API =createAxiosInstance(req, "http://" + process.env.STATUS_SERVICE_ADDRESS + process.env.STATUS_SERVICE_BASE_PATH, statusServiceApiLogger);
const LIKE_SERVICE_API = createAxiosInstance(req, "http://" + process.env.UNGUARD_LIKE_SERVICE_SERVICE_HOST + ":" + process.env.UNGUARD_LIKE_SERVICE_SERVICE_PORT, likeServiceLogger, cookieHeader);
const LIKE_SERVICE_API = createAxiosInstance(req, "http://" + process.env.LIKE_SERVICE_ADDRES, likeServiceLogger, cookieHeader);

applyTracingInterceptors(MICROBLOG_API, {span: req.span});
applyTracingInterceptors(PROXY, {span: req.span});
Expand Down
26 changes: 12 additions & 14 deletions src/frontend/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,21 +403,19 @@ async function getLikeCount(req, postId) {
return response.data
}

async function getMultipleLikeCounts(req, postIds) {
let response = await fetchUsingDeploymentBase(req, () => req.LIKE_SERVICE_API.get(`/like-service/like-count/`, { params: { postIds: postIds } }))
return response.data
}

async function insertLikeCountIntoPostArray(req, data) {
//return new Promise(async (resolve, reject) => {
let finalData = [];
await Promise.all(
data.map(async (post) => {
let postId = post.postId;
let likeData = await getLikeCount(req, postId);
let likeCount = likeData.likeCount;
let userLiked = likeData.userLiked;
post = {...post, likeCount: likeCount, userLiked: userLiked};
finalData.push(post);
})
);
return finalData;
//})
let likeData = await getMultipleLikeCounts(req, data.map(post => post.postId));

return data.map(post => {
let likeCount = likeData.likeCounts.find(likeCount => likeCount.postId == post.postId)?.likeCount ?? 0;
let userLiked = likeData.likedPosts.some(like => like.postId == post.postId);
return {...post, likeCount: likeCount, userLiked: userLiked};
});
}


Expand Down
7 changes: 6 additions & 1 deletion src/like-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM php:7.3-cli
FROM php:8.0-cli

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

Expand All @@ -12,6 +12,11 @@ ENV COMPOSER_ALLOW_SUPERUSER=1

COPY . /var/www

ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions opentelemetry

#This is faster https://github.com/composer/composer/issues/8205#issuecomment-507256979
RUN php /usr/bin/composer config --global repos.packagist composer https://packagist.org

Expand Down
137 changes: 137 additions & 0 deletions src/like-service/app/Http/Controllers/JaegerPropagator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

namespace app\Http\Controllers;

use OpenTelemetry\API\Trace\Propagation\TraceContextValidator;
use function count;
use function explode;
use function hexdec;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\SpanContext;
use OpenTelemetry\API\Trace\SpanContextInterface;
use OpenTelemetry\API\Trace\SpanContextValidator;
use OpenTelemetry\API\Trace\TraceFlags;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\ContextInterface;
use OpenTelemetry\Context\Propagation\ArrayAccessGetterSetter;
use OpenTelemetry\Context\Propagation\PropagationGetterInterface;
use OpenTelemetry\Context\Propagation\PropagationSetterInterface;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;

/**
* There's different formats used for propagation (reading/transmitting trace and span data to identify
* causal relationships between spans or, put differently, connect spans of different services)
* The PHP OpenTelemetry library seemingly only supports the W3C Trace Context format
* (https://www.w3.org/TR/trace-context/); that class is found here: OpenTelemetry\API\Trace\Propagation\TraceContextPropagator.
* This class instead uses the Jaeger Format
* (https://www.jaegertracing.io/docs/1.49/client-libraries/#propagation-format).
*
* The identifying data here is transmitted via an HTTP header called uber-trace-id, whereas
* the W3C format has two headers, traceparent and tracestate, the latter of which being vendor-specific.
* The W3C traceparent is structured like this:
* version "-" trace-id "-" parent-id "-" trace-flags ------ version seems to always be 00, trace-id is a 32-digit hex string, parent-id is a 16-digit hex string, and trace-flags is a 2-digit hex string
*
* The Jaeger uber-trace-id is strcutured thus:
* trace-id ":" span-id ":" parent-span-id ":" flags ------ trace-id is a 16- or 32-digit hex string, span-id is a 16-digit hex string, parent-span-id is a 16-digit hex string (and deprecated), flags is a 1- or 2-digit hex string
*
* The formats are very similar. Therefore, this class is mostly adapted from the official TraceContextPropagator class.
*/
final class JaegerPropagator implements TextMapPropagatorInterface
{
public const UBERTRACEID = 'uber-trace-id';

public const FIELDS = [
self::UBERTRACEID
];

private static ?self $instance = null;

public static function getInstance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}

return self::$instance;
}

/** {@inheritdoc} */
public function fields(): array
{
return self::FIELDS;
}

/** {@inheritdoc} */
public function inject(&$carrier, PropagationSetterInterface $setter = null, ContextInterface $context = null): void
{
$setter ??= ArrayAccessGetterSetter::getInstance();
$context ??= Context::getCurrent();
$spanContext = Span::fromContext($context)->getContext();

if (!$spanContext->isValid()) {
return;
}

// Build and inject the ubertraceid header
$ubertraceid = $spanContext->getTraceId() . ':' . $spanContext->getSpanId() . ':' . $spanContext->getTraceId() . ':' . ($spanContext->isSampled() ? '01' : '00');
$setter->set($carrier, self::UBERTRACEID, $ubertraceid);
}

/** {@inheritdoc} */
public function extract($carrier, PropagationGetterInterface $getter = null, ContextInterface $context = null): ContextInterface
{
$getter ??= ArrayAccessGetterSetter::getInstance();
$context ??= Context::getCurrent();

$spanContext = self::extractImpl($carrier, $getter);
if (!$spanContext->isValid()) {
return $context;
}

return $context->withContextValue(Span::wrap($spanContext));
}

private static function extractImpl($carrier, PropagationGetterInterface $getter): SpanContextInterface
{
$ubertraceid = $getter->get($carrier, self::UBERTRACEID);
if ($ubertraceid === null) {
return SpanContext::getInvalid();
}

// ubertraceid = {trace-id}:{span-id}:{parent-span-id}:{flags}
$pieces = explode(':', $ubertraceid);

// If the header does not have at least 4 pieces, it is invalid -- restart the trace.
if (count($pieces) < 4) {
return SpanContext::getInvalid();
}

[$traceId_unpadded, $spanId_unpadded, $parentSpanId_ignored, $traceFlags_unpadded] = $pieces;

// Pad in order to pass the Validators below
$traceId = str_pad($traceId_unpadded, SpanContextValidator::TRACE_LENGTH, "0", STR_PAD_LEFT);
$spanId = str_pad($spanId_unpadded, SpanContextValidator::SPAN_LENGTH, "0", STR_PAD_LEFT);
$traceFlags = str_pad($traceFlags_unpadded, TraceContextValidator::TRACE_FLAG_LENGTH, "0", STR_PAD_LEFT);

/**
* Return invalid if:
* Trace trace ID, span ID or trace flag are invalid
*/
if (!SpanContextValidator::isValidTraceId($traceId)
|| !SpanContextValidator::isValidSpanId($spanId)
|| !TraceContextValidator::isValidTraceFlag($traceFlags)
) {
return SpanContext::getInvalid();
}

// Only the sampled flag is extracted from the traceFlags (00000001)
$convertedTraceFlags = hexdec($traceFlags);
$isSampled = ($convertedTraceFlags & TraceFlags::SAMPLED) === TraceFlags::SAMPLED;

return SpanContext::createFromRemoteParent(
$traceId,
$spanId,
$isSampled ? TraceFlags::SAMPLED : TraceFlags::DEFAULT
);
}
}
21 changes: 21 additions & 0 deletions src/like-service/app/Http/Controllers/LikeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,27 @@ static function getLikeCountAndState($request, $postId)
], 200);
}

static function getMultipleLikeCountsAndStates($request)
{
$user_token = $request->cookie('jwt');
$postIds = $request->query('postIds', $request->query('postIds[]', []));

if (!self::validateToken($user_token)) {
return response()->json([
'message' => 'Unauthorized'
], 401);
}
$userId = self::extractUserIdFromToken($user_token);

$counts = DB::table('like')->select('postId', DB::raw('count(*) as likeCount'))->whereIn('postId', $postIds)->groupBy('postId')->get();
$userLiked = DB::table('like')->select('postId')->where('userId', '=', $userId)->whereIn('postId', $postIds)->get();

return response()->json([
'likeCounts' => $counts,
'likedPosts' => $userLiked
], 200);
}

/*
* Function removeLike is vulnerable to SQL-Injection-Attacks.
* When "postId" is an array, all contents of the array are added to the SQL-Bindings of the subsequent query.
Expand Down
15 changes: 11 additions & 4 deletions src/like-service/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
],
"license": "MIT",
"require": {
"php": "^7.3",
"php": "^8.0",
"fideloper/proxy": "^4.2",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "7.4.3",
"laravel/framework": "8.2",
"laravel/tinker": "^2.0"
"laravel/framework": "8.22.0",
"laravel/tinker": "^2.0",
"open-telemetry/exporter-otlp": "^1.0.0RC1",
"open-telemetry/opentelemetry-auto-laravel": "^0.0.12",
"open-telemetry/sdk": "^1.0.0RC1",
"php-http/guzzle7-adapter": "^1.0"
},
"require-dev": {
"facade/ignition": "^2.3.6",
Expand All @@ -25,7 +29,10 @@
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"php-http/discovery": true
}
},
"extra": {
"laravel": {
Expand Down
Loading

0 comments on commit dba5dc5

Please sign in to comment.