[PHP] try to reduce overhead of debug logging using Closure(same to anonymous function)
Tags: php, logging, performance, functional
Published: 2022-04-10 07:55:35

> Thanks for your visiting.
> I glad if you understand that my english level is beginner.
> I would be very happy if you find and tell me any mistake made by me.

# Overview

On this article, say about 「On PHP, use Closure(same to Anonymous Function) for trying to reduce overhead of debug logging with context data which need to operation for getting」.

I will glad if this article will be useful for you because Anonymous Function is useful on various case and language. 

Article sections are

- 1. Problems for logging debug level
    - say performance problems when we use debug level log on production services.
- 2. Try to reduce performance overhead of it using Closure
   - introduce concept of Closure simply. and try to solve the problem.
- 3. Conclusion
- APPENDIX. Things to be aware of

※ Please understand that I don't deeply say on this article about -Debug level log must be use or NOT?- 
※ Please understand that this article contains many subjective opinion of me. I will be happy for you to send it to me if you find wrong things or other opinions.

# 1. Problems for logging debug level

## 1-1. It is good that we do debug level logging very frequently?

**Be careful if doing operation about data to logging when do debug level logging.**
**※ for examples: merge arrays, get data with call some methods of objects.**

it may be useful that adding debug level logging to service for modifying and maintaining a application.

so, it may really cases that use debug level logging with adjusting threashold by each environments to do logging on only needed environments.

but, i think we may use it with a data to logging. and we may do operation about the data subconsciously because we may tend to dump data or object as debugging.

examples may are (it may be extremely examples).

```php
// array_merge
$logger->debug("request dump", array_merge($request->post, $request->get, $request->headers));

// method call (with calculating)
$logger->debug("processed data", $money->convertCurrencyTo('USD'));

// instance dump
$logger->debug("instance dump", serialize($someObject));
```
exactly, it is ineffective things when debug level is excepted from logging threshold.

if then, it is best solution that we don't use debug logging with operations of data?

## 1-2. How to solve it?

**do operation only case when it is needed.**

we approach like above for this problem.
and, we use PHP Closure Concept for it.

# 2. Try to reduce performance overhead of it using Closure

## 2-1. What is Closure on PHP?

https://www.php.net/manual/en/class.closure.php

Closure on PHP, is a class to represent Anonymous Function.

Anonymous Function is a function that don't have name and can created and called on runtime.
On PHP, we define it to variable of type of `callable` and use it as parameter, return value, and control it on runtime.

Please refer below because Nice Examples are on PHP official document.
https://www.php.net/manual/en/functions.anonymous.php

On this article, say only point of that `pass as parameter and execution it only cases which is needed - similler to lazy execution -`

※ It not perfect but Anonymous Function can allow for us do things that is similler to functional programming.
※ It may nice for you that refer to specifications of first-class function.

## 2-2. write method for debug logging with Closure

try to write like below.

```php
public function debugLog($message, Closure $closureForContext=null)
{
    // skip if logging threshold is upper from DEBUG on environment.
    // self::LOGGING_THRESHOLD refer to global setting of each environments.
    if (self::LOGGING_THRESHOLD !== Logger::DEBUG) {
        return;
    }

    // call Closure as function to get Context Array we need to do logging.
    $context = $closureForContext ? $closureForContext() : null;
    $this->monolog->debug(Logger::DEBUG, $message, $context);
}
```

## 2-3. write code to call it

when use it, pass to Closure as parameter with data providing logic.
use() syntax can allow for you to use variables in scope of it.

```php
$exampleLogger->debugLog(
    "request dump", 
    function () use ($request) {
        return array_merge($request->post, $request->get, $request->headers);
    }
);
```

## 2-4. describe it

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpyjf4idgf39ulh0ji3d.png)
 

On doing debug level logging, data providing logic will be called only cases which is needed because we make it to anonymous function. 

only adding of determination of environment and makeing logic to closure, we may can reduce overhead because logic will be not executed on production environment.

## 2-5. Simply Performance Check

It may extreme example, but we may see how much different are on elapsed time between using closure or not.
I think it has potential to bring very nice effects with very simply thinking and action.

### condition about running

- except DEBUG level from throshold of logging on PHP Symfony&Monolog
- estimate elapsed time for related code execution using `microtime(true)`
- perform 1,000,000 times for looping on same environment
- as context of log, set results of array_merge() as parameter.
    - `array_merge($request->headers, $request->query, $request->post)`

### result of elapsed time by cases of it.

|-|simply logging with context | with Closure |
|--|--|--|
|1 time| 1.0609450340271 | 0.11742901802063 |
|2 time| 1.056135892868 | 0.12697911262512 |
|3 time| 1.2411420345306 | 0.11956310272217 |
|average|1.11 sec| 0.12 sec |

※ it may more nice if we use profiler for analyzing it.

# 3. Conclusion 

we may can try to reduce of overhead using Closure(Anonymous Function) on PHP with Controling execution timing of operation.

That's conclusion.
if you need to learn more, it may nice to refer `Lazy Execution` concept.

we need to be careful using it with correct recognize, but it may bring improvement of productivity as well as reducing overhead  because it can allow for us to reduce strong coupling and make high reuseable module.

at this article, said very small part about it. 
I will glad if you can wide your idea of solving on implements a feature becuase anonymous function is very useful for us.

# Appendix. About things to be aware of

in this section, say that you may get it wrong by my mistaking of describe.

### A-1. NOT always best way that do logging DEBUG level

My opinion is that doing debug level logging is good because very useful on maintaining application quality and throuble shooting on all environments if some rules is defined.
But, it may be high ideals because it is difficult that define and maintain rules and quality on development as team. 
so, if do it, we should consider it be carefully. if do not it, we may meet annoying problems of overhead and many worthless loggings.

### A-2. NOT always nice way, Closure is.
Closure will be make a little of more overhead than simply pass array to debug log. so, not using closure may good if only consist of things that simply pass array about debug logging.

For example, if we use Closure, it make things that memory allocation for making instance of Closure, creation and destroy of Callstack for call Closure Function with Context Switching.

But, it is very useful when you frequency use debug logging with data that need to heavy operation like array_merge.

Additionally, on some cases, it may make us to difficult to analyze source code and program flow.

So, we need to use it to proper cases.

### A-3. NOT only ways only on PHP

Anonymous Function is concept which is used various programming languages.

Some differents are. but the concept is very similler in various languages. so, please try to use it more useful to other languages.