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).
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'
]
));
}
// ...
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 ;-)
I used laravel 5 and Queue. try this
$job = (new InstallTheme())->onQueue('install_theme')->delay(20);
dispatch($job);
not work
$job = (new InstallTheme())->delay(20);
dispatch($job);
work
Why the first option does not work?
upd
laravel work only if fuild "queue" in table 'jobs' = default
how to fix this?
i think setting queue.php ?
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
],
As I recall
$job = (new InstallTheme())->onQueue('install_theme')->delay(20);
dispatch($job);
puts the job into the install_theme queue while your other code puts it into the default queue. Please try to run the queue worker with this parameters.
php artisan queue:work --queue=install_theme
This should specifically process the job from this queue.
I have a Laravel 5 project that is using the bepsvpt/secure-headers package with the following config file:
config/secure-headers.php
<?php
return [
'x-content-type-options' => 'nosniff',
'x-download-options' => 'noopen',
'x-frame-options' => 'sameorigin',
'x-permitted-cross-domain-policies' => 'none',
'x-xss-protection' => '1; mode=block',
/*
* Referrer-Policy
*
* Reference: https://w3c.github.io/webappsec-referrer-policy
*
* Available Value: 'no-referrer', 'no-referrer-when-downgrade', 'origin', 'origin-when-cross-origin',
* 'same-origin', 'strict-origin', 'strict-origin-when-cross-origin', 'unsafe-url'
*/
'referrer-policy' => 'strict-origin-when-cross-origin',
'hsts' => [
'enable' => env('SECURITY_HEADER_HSTS_ENABLE', false),
'max-age' => 15552000,
'include-sub-domains' => false,
],
/*
* Content Security Policy
*
* Reference: https://developer.mozilla.org/en-US/docs/Web/Security/CSP
*
* csp will be ignored if custom-csp is not null.
*
* Note: custom-csp does not support report-only.
*/
'custom-csp' => env('SECURITY_HEADER_CUSTOM_CSP', null),
'csp' => [
'report-only' => false,
'report-uri' => env('CONTENT_SECURITY_POLICY_REPORT_URI', false),,
'upgrade-insecure-requests' => false,
'base-uri' => [
//
],
'default-src' => [
//
],
'child-src' => [
//
],
'script-src' => [
'allow' => [
//
],
'hashes' => [
// ['sha256' => 'hash-value'],
],
'nonces' => [
//
],
'self' => false,
'unsafe-inline' => false,
'unsafe-eval' => false,
],
'style-src' => [
'allow' => [
//
],
'self' => false,
'unsafe-inline' => false,
],
'img-src' => [
'allow' => [
//
],
'types' => [
//
],
'self' => false,
'data' => false,
],
/*
* The following directives are all use 'allow' and 'self' flag.
*
* Note: default value of 'self' flag is false.
*/
'font-src' => [
//
],
'connect-src' => [
//
],
'form-action' => [
//
],
'frame-ancestors' => [
//
],
'media-src' => [
//
],
'object-src' => [
//
],
/*
* plugin-types only support 'allow'.
*/
'plugin-types' => [
//
],
],
];
When I try to run the application (web request or php artisan), I get the following error:
PHP Fatal error: Cannot use empty array elements in arrays in C:\Web\myapp\config\secure-headers.php on line 4
Of course, line 4 of the file looks totally fine!
What is the issue here?
This error, which is not documented anywhere I can find online, comes from having two commas in a row with nothing between them inside the array.
In my case, this actually appeared on line 42 of the file, not line 4 as indicated by the error message, which sounds like a bug in the compiler which identifies the first item in the array instead of the actual location of the "empty array element".
NOTE: In PHP 7.2.15+, 7.3.2+, and 7.4.0+, the error message has been changed to report the line number of the previous valid element instead of the line number of the beginning of the array. While this may still be off by one or more lines, it is usually close enough to the problem to make it much easier to find.
I got the same error, while pointing at line 2, the error was on line 6.
I spent hours troubleshooting helplessly because it was a familiar code and I didn't know when an extra , got at the back of 'available' => $faker->boolean(85),
return [
'id' => $id,
'user_id' => $id,
'slug' => $slug,
'speciality' => $faker->randomElement(['Option A','Optoin B']),
'available' => $faker->boolean(85),,
'subscription_ends_at' => $faker->dateTimeBetween('-5 day', '30 day'),
'verified_at' => $faker->dateTimeBetween('-50 day', '-16 minute'),
];
Simply search your code for ,, or spaces between two commas , , on the same line as pointed out by #Moshe Katz.
This thread is a life saver.
I got this error and yes, the line indicated as where the error happened was wrong(Error was on line 10 instead of line 2 of the code below):
return Http::response(
["popularity" => 113.485,
"vote_count" => 9016,
"video" => false,
"poster_path" => "/qa6HCwP4Z15l3hpsASz3auugEW6.jpg",
"id" => 920,
"adult" => false,
"backdrop_path" => "/8KeWhoMpqbzZRyHPkTtWSLWkL5L.jpg",
"original_language" => "en",
"original_title" => "Cars",
"genre_ids" => [,
0 => 12,
1 => 16,
2 => 35,
3 => 10751,
],
"title" => "Cars",
"vote_average" => 6.8,
"overview" => "Lightning McQueen, a hotshot rookie race car driven to succeed, discovers that life is about the journey, not the finish line, when he finds himself unexpectedly detoured in the sleepy Route 66 town of Radiator Springs. On route across the country to the big Piston Cup Championship in California to compete against two seasoned pros, McQueen gets to know the town's offbeat characters.",
"release_date" => "2006-06-08",
]);
The issue was from a typo where I added a comma after the square bracket resulting in "[,"
So if you try the suggestions above and it doesn't work, look for a "[," and remove the trailing comma.