Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-arold committed May 24, 2024
1 parent 961261a commit 81d2c08
Show file tree
Hide file tree
Showing 165 changed files with 18,809 additions and 640 deletions.
2 changes: 2 additions & 0 deletions apps/eisenhower/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
},
"dependencies": {
"@shared/utils": "workspace:*",
"@effect/opentelemetry": "*",
"@opentelemetry/sdk-trace-base": "*",
"cross-fetch": "*",
"decimal.js": "*",
"effect": "*",
Expand Down
32 changes: 29 additions & 3 deletions apps/eisenhower/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import { NodeSdk } from "@effect/opentelemetry";
import {
BatchSpanProcessor,
ConsoleSpanExporter,
} from "@opentelemetry/sdk-trace-base";
import { Console, Layer, ManagedRuntime, pipe } from "effect";
import { Tag, fail, gen, succeed, sync, type Effect } from "effect/Effect";
import {
Tag,
fail,
gen,
logInfo,
succeed,
sync,
withSpan,
type Effect,
} from "effect/Effect";

export type User = { id: string; name: string };
export type UnsavedUser = { name: string };
Expand Down Expand Up @@ -69,11 +83,23 @@ export const make = gen(function* () {
});
});

const CONTEXT = Layer.merge(UserRepository.live(), UUIDProvider.layer());
const NodeSdkLive = NodeSdk.layer(() => ({
resource: { serviceName: "Workshop" },
spanProcessor: new BatchSpanProcessor(new ConsoleSpanExporter()),
}));

const CONTEXT = Layer.merge(UserRepository.live(), NodeSdkLive);
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
yield* logInfo(`Saving user: Alice`);
return yield* UserRepository.save({ name: "Alice" });
});
}).pipe(
withSpan("Save User", {
attributes: {
name: "Alice",
},
})
);

console.log(RUNTIME.runSync(program));
5 changes: 5 additions & 0 deletions apps/slidev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
"export": "slidev export"
},
"dependencies": {
"@effect/opentelemetry": "*",
"@opentelemetry/sdk-trace-base": "*",
"@opentelemetry/sdk-metrics": "*",
"@opentelemetry/sdk-trace-web": "*",
"@opentelemetry/sdk-trace-node": "*",
"@slidev/theme-default": "*",
"@slidev/theme-seriph": "*",
"effect": "*",
Expand Down
49 changes: 49 additions & 0 deletions apps/slidev/public/waterfall-trace.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
301 changes: 301 additions & 0 deletions apps/slidev/slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -4074,5 +4074,306 @@ Docs can be found [here](https://effect.website/docs/guides/observability/teleme


<!--
TODO: I don't know much about metrics
-->

---
---

# Tracing

> Tracing in software engineering refers to the process of capturing and recording information about the execution of a software program.
<em v-click>Thanks Wikipedia, you can go home ... 😒</em>

<ul class="mt-4">
<li v-click>Tracing is a form of observability</li>
<li v-click>It provides a detailed view of the execution of a program</li>
<li v-click>Across (micro)services</li>
<li v-click>Can be used to identify bottlenecks and performance issues</li>
<li v-click>Can be used to debug complex systems</li>
</ul>


<!--
-->


---
---

# Tracing in Effect: Spans

> A span represents a unit of work or operation. It typically contains:
<ul class="mt-4">
<li v-click>Name: Describes the operation being tracked.</li>
<li v-click>Time-Related Data: Timestamps to measure when the operation started and how long it took.</li>
<li v-click>Structured Log Messages: Records essential information during the operation.</li>
<li v-click>Metadata (Attributes): Additional data that provides context about the operation.</li>
</ul>


<!--
-->

---
---

# Tracing in Effect: Traces

> A trace records the paths taken by requests as they propagate through the system.
<ul class="mt-4">
<li v-click>Consists of one or more spans</li>
<li v-click>The first span is the "root"</li>
<li v-click>The rest are children of the root</li>
<li v-click>Usually visualized as a waterfall diagram</li>
</ul>


<!--
-->

---
---

# Tracing in Effect: Traces

<img src="/waterfall-trace.svg" class="m-auto h-auto w-100 h-100 rounded shadow" />


<!--
-->

---
---

# Let's Create A Span

````md magic-move

```ts
// 👇 Our original program
const CONTEXT = Layer.merge(
UserRepository.live(),
UUIDProvider.layer()
);
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
return yield* UserRepository.save({ name: "Alice" });
});

console.log(RUNTIME.runSync(program));
```

```ts
const CONTEXT = Layer.merge(
UserRepository.live(),
UUIDProvider.layer()
);
const RUNTIME = ManagedRuntime.make(CONTEXT);

// 👇 With a Span
const program = gen(function* () {
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User"));

console.log(RUNTIME.runSync(program));
```

```ts
const CONTEXT = Layer.merge(
UserRepository.live(),
UUIDProvider.layer()
);
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User", {
// 👇 Custom attribute
attributes: {
name: "Alice",
}
}));

console.log(RUNTIME.runSync(program));
```

```ts
const CONTEXT = Layer.merge(
UserRepository.live(),
UUIDProvider.layer()
);
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
// 👇 Will appear in the trace as an event
yield* logInfo(`Saving user: Alice`);
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User", {
attributes: {
name: "Alice",
}
}));

console.log(RUNTIME.runSync(program));
```

````

<!--
Here we should discuss how the log functions integrate with tracing, and how logs will appear
as events in the trace.
-->

---
---

# Let's Try It Out!

```ts {monaco-run} {autorun:false}
import { gen, Layer, ManagedRuntime, withSpan, logInfo } from "./Effect";
import { UserRepository, UUIDProvider } from "./UsersV2";

const CONTEXT = UserRepository.live();
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
// 👇 Will appear in the trace as an event
yield* logInfo(`Saving user: Alice`);
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User", {
attributes: {
name: "Alice",
}
}));

console.log(RUNTIME.runSync(program));
```

---
---

# It Is The Same As Before

<div>❓ Why?</div>
<div v-click>💡 We didn't set the corresponding service up!</div>

<!--
Ask them if they have an idea why we don't see any change before revealing the answer
-->

---
---

# Setting Up Tracing

````md magic-move

```ts
const CONTEXT = UserRepository.live();
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User", {
attributes: {
name: "Alice",
}
}));

console.log(RUNTIME.runSync(program));
```

```ts
// 👇 We use the NodeSdk from @effect/opentelemetry
const NodeSdkLive = NodeSdk.layer(() => ({
resource: { serviceName: "Workshop" },
// 👇 And the appropriate processor / exporter from @opentelemetry
spanProcessor: new BatchSpanProcessor(new ConsoleSpanExporter())
}))

const CONTEXT = UserRepository.live();
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User", {
attributes: {
name: "Alice",
}
}));

console.log(RUNTIME.runSync(program));
```

```ts
const NodeSdkLive = NodeSdk.layer(() => ({
resource: { serviceName: "Workshop" },
spanProcessor: new BatchSpanProcessor(new ConsoleSpanExporter())
}))

// 👇 We add the service to the context
const CONTEXT = Layer.mergeAll(UserRepository.live(), NodeSdkLive);
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User", {
attributes: {
name: "Alice",
}
}));

console.log(RUNTIME.runSync(program));
```

````

---
---

# A Working Example

```ts {monaco-run} {autorun:false}
import { gen, Layer, ManagedRuntime, withSpan } from "./Effect";
import { UserRepository, UUIDProvider } from "./UsersV2";
import { NodeSdk } from "@effect/opentelemetry";
import { BatchSpanProcessor, ConsoleSpanExporter } from "@opentelemetry/sdk-trace-base";

const NodeSdkLive = NodeSdk.layer(() => ({
resource: { serviceName: "Workshop" },
spanProcessor: new BatchSpanProcessor(new ConsoleSpanExporter())
}))

const CONTEXT = Layer.mergeAll(UserRepository.live(), NodeSdkLive);
const RUNTIME = ManagedRuntime.make(CONTEXT);

const program = gen(function* () {
return yield* UserRepository.save({ name: "Alice" });
}).pipe(withSpan("Save User", {
attributes: { name: "Alice" }
}));

console.log(RUNTIME.runSync(program));
```

<!--
This will show up in the browser console as an Object. We can also add a logInfo to see it appear in events.
We can also discuss other types of exporters and processors.
-->

---
---


```ts
const program = gen(function* () {
return yield* Questions.get();
}).pipe(withSpan("Questions", {
attributes: { name: "Are there?" }
}));
```
Loading

0 comments on commit 81d2c08

Please sign in to comment.