arjan

arjan

Hi,

I am writing the Elixir integration for AppSignal, an application metrics solution. As of such, I am looking for a way to decorate functions in a developer-friendly way, so that these functions are automagically wrapped with library calls to measure the time it took to execute them (and send that info off to the backend).

As instrumenting functions is a common task while analyzing an application’s performance I want to minimize the amount of work the developer has to do to add instrumentation. As of such I have found two ways to do the instrumentation, both of which have its drawbacks:

1 - an instrumented do .... end block, in which you define the functions example here. Drawback of this method is that inside the block, everything is indented one level deeper, causing all the code to change while you have in fact just added 2 lines of code;making merging code changes harder;

2 - replace def foo() by def_instrument foo() (or similar) and use Kernel.def (like suggested here); the downside of this method is that it just “feels” weird to not read def, plus editor syntax highlighting breaks.

Are there any alternatives to tackle this? Ideally my solution would be a (Python / Java) decorator kind of syntax like this:

@instrumented
def foo(bar) do
  ...

But I am not sure that this is technically possible. I would love some input from the community on this!

cheers,
Arjan

Showing Posts 11 to 20

arjan

arjan OP

Using an @ attribute does not work, I think, but creating a decorate() macro does, see this gist.

That syntax is pretty OK, if you ask me:

decorate()
def i_am_instrumented(bar) do
  ..

Next step: creating macros to create decorator macros :stuck_out_tongue:

OvermindDL1

OvermindDL1

iex> quote do
...> @instrumented
...> def hello, do: "world"
...> end
{:__block__, [],
 [{:@, [context: Elixir, import: Kernel], [{:instrumented, [], Elixir}]},
  {:def, [context: Elixir, import: Kernel],
   [{:hello, [context: Elixir], Elixir}, [do: "world"]]}]}

Nah, that is fine if it is only for the AST to go over, it only matters to set something if you want to access it post-ast.

You could always do something like this too:

defmodule SomeUserModule do
  use Instrumented
  @instrumented hello: 0
  @instrumented anotherFun: 4
  # ...

  def hello, do: "world"

  # .. lots of more functions
end

Hah, yep, could make a library for it all.

arjan

arjan OP

Doing just that! Right now I’m generating macros. Does not look so nice (no @) but it works pretty well. Let me know if you have a better way of doing this :slight_smile:

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

One this thread hasn’t really talked about is whether the decorator pattern is actually a good idea in Elixir. I’m not entirely convinced that it is.

With instrumentation for example very frequently the caller site is the thing that should care about whether or not a given function call is instrumented. If you mark a function as instrumented with a decorator then every call to it is gonna have some kind of side effect whether that is actually desired or not.

arjan

arjan OP

I partly agree with you… however, I use Java a lot which got my mind twisted in the wrong direction maybe :slight_smile:

The use cases that I see right now are:

  • For instrumentation, it is nice to use decorators because they allow you to turn it on or off with the addition/deletion of a single line of code.
  • I also can see it working for Phoenix controllers, a bit like putting a plug in a controller but only for a single function call.
  • Or for adding precondition checks to a function.

Anyway, I’ve wrapped it into a library: GitHub - arjan/decorator: Function decorators for Elixir · GitHub

OvermindDL1

OvermindDL1

I think it was the :trace module could allow you to hook functions, so you could define things to instrument based on module name and function name from the config or so?

arjan

arjan OP

Also found a way to do it with @ but downside there is that it breaks “regular” module attributes..

OvermindDL1

OvermindDL1

How so?

arjan

arjan OP

Because I do import Kernel, except: [@: 1]

and from my own @ macro I cant seem to call the Kernel.@ macro

arjan

arjan OP

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews