Laravel log file specific to a package - php

I'm writing a couple of laravel packages and I'm wondering if it is possible to have the package write to a specific log file but only for messages related to the package?
I tried making a logging.php file in the packages/myorg/mypackage/config (below) but it doesn't seem to do anything.
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
return [
'default' => env('LOG_CHANNEL', 'stack'),
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single'],
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/mypackage.log'),
'level' => env('LOG_LEVEL', 'debug'),
]
]
];
I am using "jeroen-g/laravel-packager" to set up the packages. It appears to manually load the mypackage.config in the ServiceProvider bootForConsole
protected function bootForConsole(): void
{
// Publishing the configuration file.
$this->publishes([
mypackage.'/../config/mypackage.php' => config_path('mypackage.php'),
], 'mypackage.config');
}
I'm not sure how to add custom logging to that though. I'm still learning Laravel and I'm not quite sure what or how the main applications config/logging.php is read so I'm not quite sure how to inject a custom version for an add-on package.
EDIT:
I found a post that suggested using the following in the ServiceManager boot() method:
$this->app->make('config')->set('logging.channels.mychannel', [
/* settings */
]);
I used the package config to set a 'logging' => [ 'channels' => [ 'mychannel' => [ /* settings */ ] ] ] and could then do the same thing as above with:
$this->app->make('config')->set('logging.channels.mychannel', config('mypackage.logging.channels.mychannel');
But that still required something in the code. The next best thing I have found thus far is to change my config/logging.php to config/logging.channels.php and include something like:
return [
'mychannel' => [
'driver' => 'single',
'path' => storage_path('logs/mypackage.log'),
'level' => env('LOG_LEVEL', 'debug'),
]
];
Then in the service provider register() method add:
$this->mergeConfigFrom(__DIR__ . '/../config/logging.channels.php', 'logging.channels');
I tried doing it from the original 'logging.php' with channels array nested in a 'logging' key, but array_merge doesn't appear to merge the nested elements so my channel never showed up in logging.channels.
I'm not sure if this is ideal, however. I'd still like to know if there is a 'better' or best practices way of adding custom package logging parameters and whether there is a need to publish it in any way (and how).

Related

Monolog MongoDBHandler having BindingResolutionException error in Laravel 8

I tried to create a mongodb logging channel
'mongo' => [
'driver' => 'monolog',
'handler' => \Monolog\Handler\MongoDBHandler::class,
'formatter' => \Monolog\Formatter\MongoDBFormatter::class,
'handler_with' => [
'mongo' => new \MongoDB\Client("mongodb://localhost:27017"),
'database' => 'testdb',
'collection' => 'testcoll'
]
],
However, im getting error:
Illuminate\Contracts\Container\BindingResolutionException(code: 0): Unresolvable dependency resolving [Parameter #0 [ <required> $mongodb ]] in class Monolog\Handler\MongoDBHandler
The error is only resolved when I tried to add type hint to the class constructor but obviously I can't do that since it's a package:
public function __construct(Client<<if I add this it works>> $mongodb, string $database, string $collection, $level = Logger::DEBUG, bool $bubble = true)
Any solution for this?
So, I wanted to add here a complete answer because this post is the first one that shows up when looking for adding a mongo logger, and since the answer is buried in the comments, I wanted to add a proper answer.
The solution was to change the key mongo to mongodb in the handler_with array.
Leaving the working code like this:
'mongo' => [
'driver' => 'monolog',
'handler' => \Monolog\Handler\MongoDBHandler::class,
'formatter' => \Monolog\Formatter\MongoDBFormatter::class,
'handler_with' => [
'mongodb' => new \MongoDB\Client("mongodb://localhost:27017"),
'database' => 'testdb',
'collection' => 'testcoll'
]
],
Also, you could add the following element at the same level as formatter to set a custom max level of nesting. This is because, by default, the document stored cannot have a depth greater than 3, and it's automatically converted to "[...]" in the log.
'formatter_with' => [
'maxNestingLevel' => 10
],
Warning, in the probable event of a recursion, or an incredibly deep array, it can cause problems in mongo, because it doesn't support more than 100 levels of nesting, source.
According to the Laravel 8.x doc:
'mongo' => [
'driver' => 'monolog',
'handler' => \Monolog\Handler\MongoDBHandler::class,
'formatter' => \Monolog\Formatter\MongoDBFormatter::class,
'with' => [ // <-- This is `with` instead of `handler_with`
// 'mongodb' => new \MongoDB\Client("mongodb://localhost:27017"), <-- This line will cause an error in `php artisan config:cache`
'database' => 'testdb',
'collection' => 'testcoll'
],
],
So you need to configure the service for MongoDBHandler. as you mentioned with a look at the handler source code the first argument is $mongodb.
public function __construct($mongodb, string $database, string $collection, $level = Logger::DEBUG, bool $bubble = true)
and to be able to resolve this dependency we can configure service container:
// AppServiceProvider.php
// ...
public function register() {
$this->app->when(\Monolog\Handler\MongoDBHandler::class)
->needs('$mongodb')
->give(app(
\MongoDB\Client::class,
[
'uri' => 'mongodb://localhost:27017'
]
));
}
// ...

Yii2 Debugbar is not showing the file line

I am trying to see the traceLine on Yii2 debug bar like explains in (https://github.com/yiisoft/yii2-debug#open-files-in-ide), but I can't see it.
I have Yii2 2.0.28 and debug-bar 2.1.9 with php 7.2.19
For example: is there any way, inspecting any debug bar’s panel, to know which line of my code thrown a trace/profile action in the debug bar?
Or how can I see where is located any query I am seeing in the database panel?
My config:
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
'traceLine' => '{file}:{line}',
'allowedIPs' => ['*'],
'panels' => [
'db' => [
'class' => 'yii\debug\panels\DbPanel',
'defaultOrder' => [
'seq' => SORT_ASC
],
'defaultFilter' => [
'type' => 'SELECT'
]
],
],
];
There are two properties in configuration that affect how the files are displayed in logs in debug bar.
1) traceLine property of debug module. This property contains a template for displaying single line of trace.
In configuration it may look like this
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
'traceLine' => '{file}:{line}',
// ... other debug module configurations
]
2) traceLevel property of log component. This affect how many calls will be displayed in trace. The calls of framework's classes are not displayed in debug toolbar, only your files are displayed.
The configuration might look like this
'components' => [
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
// ... other log component configurations
],
// ... other components
],
In the example the traceLevel depends on YII_DEBUG constant. This is used to avoid performance issues in production environments. This is also how traceLevel is set in default yii2 application templates.
The YII_DEBUG constant is usually set in index.php file like this
defined('YII_DEBUG') or define('YII_DEBUG', true);

The "access_key" option must be provided to use fixer.io

For the currency conversion i am using "florianv/laravel-swap": "^1.1" library. Florianv/Laravel-swap.
As Fixer.io has changed its implementation, it is necessary to pass the access_key with the request, and because of that i am getting this error: "InvalidArgumentException: The "access_key" option must be provided to use fixer.io in /var/www/project/project-files/vendor/florianv/exchanger/src/Service/Fixer.php:51".
I registered and got the access_key.
I updated the library using composer and now i can see three constants in the vendor/florianv/exchanger/src/Service/Fixer.php.
const ACCESS_KEY_OPTION = 'access_key';
const LATEST_URL = 'http://data.fixer.io/api/latest?base=%s&access_key=%s';
const HISTORICAL_URL = 'http://data.fixer.io/api/%s?base=%s&access_key=%s';
To pass the access key i tried this:
I have a swap.php in config folder which looks something like this:
return [
'options' => [
'cache_ttl' => 86400, // 24 hours.
'cache_key_prefix' => 'currency_rate'
],
'services' => [
'fixer' => true,
],
'currency_layer' => [
'access_key' => 'asdfas7832mw3nsdfa776as8dfa', // Your app id
'enterprise' => true, // True if your AppId is an enterprise one
],
'cache' => env('CACHE_DRIVER', 'file'),
'http_client' => null,
'request_factory' => null,
'cache_item_pool' => null,
];
This had one more option which was commented, i enabled and passed the access_key in it but it doesn't work.
I also added it in services block below 'fixer => true'.
'currency_layer' => [
'access_key' => 'asdfas7832mw3nsdfa776as8dfa'
]
Also in options block:
'options' => [
'cache_ttl' => 86400, // 24 hours.
'cache_key_prefix' => 'currency_rate',
'access_key'=>'7ca208e9136c5e140d6a14427bf9ed21'
],
I tried with adding access_key in config/services.php file but it also didn't work.
'fixer' => [
'access_key' => 'asdfas7832mw3nsdfa776as8dfa'
],
Even i tried, adding to env file and calling from there, but no success. How do i pass the access_key, can anyone help me on this, what should be the approach.
vendor/florianv/exchanger/src/Service/Fixer.php -> don't touch the constant (that was my own error).
Pass the options-array by creating the Builder:
$options = ['access_key' => 'YourGeneratedAPIKeyAtCurrencyLayer'];
$this->exchangeSwap = (new Builder($options))
->add('fixer', $options )
->build();
I hope I could help ;-)

Setting/retrieving mode in Slim Framework V3

I am new to Slim Framework (PHP). I was going through tutorials and testing some code and tried the following:
$app=new App([
'mode'=>file_get_contents(INC_ROOT . '/mode.php')
]);
echo $app->config('mode');
The output was blank.
It seems the function config() works with V2, however I am using V3. What am I doing wrong?
Slim 3 no longer has a config method. Instead, you must add configuration settings through the dependency injection container:
$app = new \Slim\App([
'settings' => [
'mode' => true
]
]);
$container = $app->getContainer();
echo $container->get('settings')['mode'];
A few things worth noting:
Slim 3 no longer handles managing different versions of configuration settings through a mode setting. So, you can set a value for a setting variable called mode as I've demonstrated here, but it won't actually do anything (i.e., Slim won't use it to determine your environment).
As an alternative, you can check out userfrosting/Config, a library we've been working on that can search multiple directories and different environment configuration files, merging together their contents:
/path/to/config/default.php
return [
'contacts' => [
'housekeeper' => [
'name' => 'Alex',
'email' => 'alex#cleansthetoilet.com'
]
]
];
/path/to/config/production.php
return [
'contacts' => [
'housekeeper' => [
'email' => 'alex#istheboss.com'
]
],
'database' => [
'password' => 'sup3rC-cr3t'
]
];
index.php
$app = new \Slim\App();
$container = $app->getContainer();
// Site config object (separate from Slim settings)
$container['config'] = function ($c) {
// Create and inject new config item
$config = new \UserFrosting\Config\Config();
$config->setPaths([
'/path/to/config'
]);
$config->loadConfigurationFiles('production');
return $config;
};
This will recursively merge in the settings from development.php with those in default.php, updating settings with the same name and scope as necessary:
Running print_r($container['config']); returns:
[
'contacts' => [
'housekeeper' => [
'name' => 'Alex',
'email' => 'alex#istheboss.com'
]
],
'database' => [
'password' => 'sup3rC-cr3t'
]
]
Notice that the value of contacts.housekeeper.email has been updated to 'alex#istheboss.com', and that the database config info has been merged in. Incidentally, you can also access config settings using the more convenient "dot syntax":
$config = $container->get('config');
echo $config['contacts.housekeeper.email'];
// Easier to type instead of $config['contacts']['housekeeper']['email'];
We recommend injecting this as a separate config service in Slim, rather than using their settings array.
You can combine this with phpdotenv to load settings from your system environment, or any .env files you create:
/path/to/config/production.php
return [
'database' => [
'password' => getenv('DB_PASSWORD')
]
];

Override Yii2 assetManager config in controller

I use yii-jui to add some UI elements in the views such as datePicker. In the frontend\config\main-local.php I set the following to change the theme used by the JqueryUI:
$config = [
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'gjhgjhghjg87hjh8878878',
],
'assetManager' => [
'bundles' => [
'yii\jui\JuiAsset' => [
'css' =>
['themes/flick/jquery-ui.css'],
],
],
],
],
];
I tried the following to override this configuration item in the controller actions method:
public function actions() {
Yii::$app->components['assetManager'] = [
'bundles' => [
'yii\jui\JuiAsset' => [
'css' =>
['themes/dot-luv/jquery-ui.css'],
],
],
];
return parent::actions();
}
Also I tried to set the value of Yii::$app->components['assetManager'] shown above to the view itself (it is partial view of form _form.php) and to the action that calls this view (updateAction). However, all this trying doesn't be succeeded to change the theme. Is there in Yii2 a method like that found in CakePHP such as Configure::write($key, $value);?
You should modify Yii::$app->assetManager->bundles (Yii::$app->assetManager is an object, not an array), e.g.
Yii::$app->assetManager->bundles = [
'yii\jui\JuiAsset' => [
'css' => ['themes/dot-luv/jquery-ui.css'],
],
];
Or if you want to keep other bundles config :
Yii::$app->assetManager->bundles['yii\jui\JuiAsset'] = [
'css' => ['themes/dot-luv/jquery-ui.css'],
];
You are going about this all wrong, you want to change the JUI theme for 1 controller alone because of a few controls. You are applying 2 css files to different parts of the website that have the potential to change styles in the layouts too. The solution you found works but it is incredibly bad practice.
If you want to change just some controls do it the proper way by using JUI scopes.
Here are some links that will help you:
http://www.filamentgroup.com/lab/using-multiple-jquery-ui-themes-on-a-single-page.html
http://jqueryui.com/download/
In this way you are making the website easier to maintain and you do not create a bigger problem for the future than you what solve.

Categories