I'm using the following change my log path:
\Log::useDailyFiles(...)
But I still get log entries in /storage/logs/. How can I use only my log path?
Laravel already registers an instance of the logger when bootstrapping the ConfigureLogging class. So when you use Log::useDailyFiles() you're just adding an additional log handler, that's why you also get log entries in the standard storage/logs/laravel.log.
To override the default log handler, Laravel offers the configureMonologUsing method available on the application instance. So in your bootstrap/app.php file just before the return $app; statement, add the following:
$app->configureMonologUsing(function($monolog) use ($app) {
$monolog->pushHandler(
(new Monolog\Handler\RotatingFileHandler(
// Set the log path
'/custom/path/to/custom.log',
// Set the number of daily files you want to keep
$app->make('config')->get('app.log_max_files', 5)
))->setFormatter(new Monolog\Formatter\LineFormatter(null, null, true, true))
);
});
The second parameter passed to the RotatingFileHandler tries to get a configuration value for log_max_files from config/app.php to determine how many daily log files it should keep, and if it doesn't find one it defaults to 5. If you want to keep an unlimited number of daily log files just pass 0 instead.
You can read more about logging configuration in the Laravel Documentation.
Laravel 5 : bootstrap/app.php
CUSTOM DAILY LOG :
$app->configureMonologUsing(function($monolog) use ($app) {
$monolog->pushHandler(
(new Monolog\Handler\RotatingFileHandler(
// Set the log path
$app->storagePath().'/logs/app_error.log',
// Set the number of daily files you want to keep
$app->make('config')->get('app.log_max_files', 30)
))->setFormatter(new Monolog\Formatter\LineFormatter(null, null, true, true))
);
});
SINGLE LOG :
$app->configureMonologUsing(function($monolog) use ($app) {
$handler = new Monolog\Handler\StreamHandler($app->storagePath().'/logs/app_error.log');
$handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
$monolog->pushHandler($handler);
});
For those still coming across this post, I believe changing your log file location is now easier in newer versions of Laravel. I am currently using 8.x.
In your /config/logging.php, you can define the path for your single and daily logs. Then, update whichever one you are looking to change.
'single' => [
'driver' => 'single',
'path' => "/your/desired/log/path/file.log", // edit here
'level' => env('LOG_LEVEL', 'debug'),
],
'daily' => [
'driver' => 'daily',
'path' => "/your/desired/log/path/file.log", // edit here
'level' => env('LOG_LEVEL', 'debug'),
'days' => 14,
]
Related
Is there a way to disable the database logging of laravel when a job failed?
For example I'm just trying to write a log message, which would enough for this specific job:
job.php
public function handle()
{
//making an API request to an external API, storing some data inside cache
}
public function failed(Throwable $exception)
{
Log::info("external API update failed");
}
I already tried to edit the config/queue.php file by:
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => null,
'table' => null,
],
This doesn't work, any idea how to get the database logging of failed jobs disabled?
I believe you have to set config/queue.php to the following:
'failed' => [
'driver' => null
'database' => null,
'table' => null,
],
You should be able to find clues within the laravel/framework folder within the vendor folder in your project, e.g.
vendor/laravel/framework/src/Illuminate/Queue/DatabaseFailedJobProvider.php.
The saving to database is done in the DatabaseFailedJobProvider class, the log function specifically.
Based on the QueueServiceProvider's registerFailedJobServices function, you would need to set the driver to null or the 'null' string in order to get it to run the NullFailedJobProvider, where the log function is empty.
Like the state itself, I want to create multiple Log files for different processes.
I am using Laravel-8.
I have also created the 1 logging file with the help of logging.php in the config folder.
I want to keep track of my created commands with their own separate log file.
How can I create my separate log file for that commands?
I did this by having only a log for daily. "config/logging.php"
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['daily'],
'ignore_exceptions' => false,
]...,
]
You should use config/logging.php to create custom channel for each command
e.g.
'CHANNEL_NAME' => [
'driver' => 'single',
'path' => storage_path('logs/LOG_FILE_NAME.log'),
'level' => 'DESIRED_LEVEL',
],
and change CHANNEL_NAME, LOG_FILE_NAME and DESIRED_LEVEL values as you want.
Note: 'level' => 'DESIRED_LEVEL' is optional. it can be single level or array of levels (laravel v8.x).
Then when you want to log anything in your command class, Log like following code
Usage:
Log::channel('CHANNEL_NAME')
->info('Something happened!');
Below code will generate custom log file.
try{
//Your code here
}catch(\Exception $e){
$cusLog = new Logger('stack');
$err_file_name = $task_id."_".time();
$syncHistory['file_name'] = $err_file_name;
$cusLog->pushHandler(new StreamHandler(storage_path('logs/'.$err_file_name.'.log')), Logger::INFO);
$cusLog->info('error', ['Exception'=>$e->getTraceAsString(),'message'=>$e->getMessage()]);
}
Hope this will be useful.
By default Laravel Vapor pushes the laravel.log file to strerr output. Which is the picked up by Lambda and thrown to Cloudwatch. Quite hard to look through unless you are looking via the Vapor UI.
Look for an easy way to do this and push them directly to Cloudwatch (with multiple files).
Firstly added this awesome Library
composer require maxbanton/cwh
Then add this to your log config...
'cloudwatch' => [
'driver' => 'custom',
'via' => \App\Logging\CloudWatchLoggerFactory::class,
'formatter' => Monolog\Formatter\JsonFormatter::class,
'cloudwatch_stream_name' => 'laravel',
'sdk' => [
'region' => 'eu-west-1',
'version' => 'latest',
'credentials' => [
'key' => env('AWS_CW_ACCESS'),
'secret' => env('AWS_CW_SECRET')
]
],
'retention' => 730,
'level' => 'debug',
],
You'll need to add AWS_CW_ACCESS and AWS_CW_SECRET keys for an IAM user with access to Cloudwatch.
Then add App/Logging/CloudWatchLoggerFactory.php with the following contents..
<?php
namespace App\Logging;
use Aws\CloudWatchLogs\CloudWatchLogsClient;
use Maxbanton\Cwh\Handler\CloudWatch;
use Monolog\Formatter\JsonFormatter;
use Monolog\Logger;
class CloudWatchLoggerFactory
{
/**
* Create a custom Monolog instance.
*
* #param array $config
* #return \Monolog\Logger
*/
public function __invoke(array $config)
{
$sdkParams = $config["sdk"];
$tags = $config["tags"] ?? [ ];
$name = $config["name"] ?? 'cloudwatch';
// Instantiate AWS SDK CloudWatch Logs Client
$client = new CloudWatchLogsClient($sdkParams);
// Log group name, will be created if none
$groupName = config('app.name') . '-' . config('app.env');
// Log stream name, will be created if none
// $streamName = config('app.hostname');
$streamName = $config["cloudwatch_stream_name"];
// Days to keep logs, 14 by default. Set to `null` to allow indefinite retention.
$retentionDays = $config["retention"];
// Instantiate handler (tags are optional)
$handler = new CloudWatch($client, $groupName, $streamName, $retentionDays, 10000, $tags);
$handler->setFormatter(new JsonFormatter());
// Create a log channel
$logger = new Logger($name);
// Set handler
$logger->pushHandler($handler);
//$logger->pushProcessor(new CompanyLogProcessor()); //Use this if you want to adjust the JSON output using a log processor
return $logger;
}
}
You can then use that as any log... Ie Log::channel('cloudwatch')->info('hey');
To force the default laravel.log to here AND show in vapor just add this as a stack
'vapor' => [
'driver' => 'stack',
'channels' => ['stderr', 'cloudwatch'],
'ignore_exceptions' => false,
],
Then set logging.default setting to vapor in your envvars.
If you want additional logging channels just copy the cloudwatch channel setting with a new one and make sure you adjust the cloudwatch_stream_name.
Thanks to the other answer I found on Stackoverflow helping me get to here. I wanted to log this directly under answer for Laravel Vapor as I imagine many others will get stuck trying to do this!
Documentation says to create directory with file by path: resources/lang/xx/validation.php.
Then add content of validation words:
return ['custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
]];
How to use this for Creating Form Requests where is going validation?
This is just for deploying custom validation messages, e.g. whenever 'email' is 'required' it will return this message in place of the default message: The email field is required.
If you want to replace all the other messages take a look at /resources/lang/en/validation.php here and see all the basic messages which you can replace with your local language versions in your /resources/lang/xx/validation.php
If you want a custom message, find the custom array at line 130 and change to:
'custom' => [
'price' => [
'required' => 'The price is required! Please supply one.',
],
],
Then, be sure to set your app locale, e.g.
Route::get('welcome/{locale}', function ($locale) {
App::setLocale($locale);
//
});
Or if your entire app is in another language, you could set locale in your /config/app.php on line 81.
Your usual validator will now use the messages in /resources/lang/locale/validation.php
I want to send Monolog logs from my Laravel 5.1 application to Loggly.com online log management service. From all possible environment, including local development.
I have found some outdated libs and complicated ways to do this. So I ended up with very simple solution. Actually, Laravel Monolog Handler already have Loggly Handler out of the box.
Add config info to config/services.php:
'loggly' => array(
'key' => 'ENTER_YOUR_LOGGLY_TOKEN_HERE',
'tag' => 'ProjectName_' .strtolower(env('APP_ENV')),
),
Than add Monolog handler in bootstrap/app.php, before $app is returned:
/*
|--------------------------------------------------------------------------
| Setup Loggly Handler
|--------------------------------------------------------------------------
*/
$app->configureMonologUsing(function($monolog) {
$handler = new \Monolog\Handler\LogglyHandler(config('services.loggly.key'),\Monolog\Logger::DEBUG);
$handler->setTag(config('services.loggly.tag'));
$monolog->pushHandler($handler);
});
Voila! You are getting your Monolog Logs in Loggly dashboard.
UPDATE: (thanks #thitami)
Based on laravel.com/docs/5.6/upgrade
The configureMonologUsing Method
If you were using the configureMonologUsing method to customize the Monolog instance for your application, you should now create a custom Log channel. For more information on how to create custom channels, check out the full logging documentation.
I was able to manage having Laravel's default local log behaviour, and pushing to Loggly in the same time, by tweaking mladen-janjetovic's code a bit. Tested on Laravel 5.3
config/services.php:
'loggly' => [
'key' => 'ENTER_YOUR_LOGGLY_TOKEN_HERE',
'tag' => 'ProjectName_' .strtolower(env('APP_ENV')),
],
bootstrap/app.php:
/*
|--------------------------------------------------------------------------
| Push to Loggly, and save locally.
|--------------------------------------------------------------------------
*/
$app->configureMonologUsing(function($monolog) use ($app) {
$log = $app->make(Illuminate\Log\Writer::class);
$logglyHandler = new \Monolog\Handler\LogglyHandler(config('services.loggly.key'));
$logglyHandler->setTag(config('services.loggly.tag'));
if (config('app.env') == 'production')
{
// Push to Loggly and save local if in production
$log->getMonolog()->pushHandler($logglyHandler);
$log->useFiles(storage_path('/logs/laravel.log'));
}
else
{
// Otherwise, save only locally
$log->useFiles(storage_path('/logs/laravel.log'));
}
});
Alternatively, you may use Monolog-Cascade to do this.
Monolog-Cascade is a Monolog extension that allows you to set up and configure multiple loggers and handlers from a single config file.
Here is a sample config file for Monolog-Cascade using Loggly. This would log to you stdOut and to Loggly:
---
handlers:
console:
class: Monolog\Handler\StreamHandler
level: DEBUG
stream: php://stdout
error_loggly_handler:
class: Monolog\Handler\LogglyHandler
level: ERROR
token: xxxx-xxxx-xxxxxxxx
tags: [cascade, waterfall]
loggers:
my_logger:
handlers: [console, error_loggly_handler]
If you're interested, here is a blog post on Cascade => https://medium.com/orchard-technology/enhancing-monolog-699efff1051d
[Disclaimer]: I am the main contributor of Monolog-Cascade.
Got mine working with little configuration with Laravel 8.
Just use the built-in monolog handler for Loggly.
Edit your app/config/logging.php
use Monolog\Handler\LogglyHandler;
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single', 'loggly'],
'ignore_exceptions' => false,
],
'loggly' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => LogglyHandler::class,
'with' => [
'token' => env('LOGGLY_TOKEN'),
],
],
]
For more advanced logging (for my case I need to set the tag as it was missing in the built-in handler's constructor.
Copy the built-in handler where you can find it within vendor folder
(e.g: vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php) into your app folder of choice (e.g: app/Logging/CustomLogglyHandler.php).
Modify the constructor to set the tags, and you need to change some of the imports as we're on different namespaces.
// app/Logging/CustomLogglyHandler.php
namespace App\Logging;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Handler\MissingExtensionException;
use Monolog\Logger;
use Monolog\Formatter\FormatterInterface;
use Monolog\Formatter\LogglyFormatter;
use function array_key_exists;
use CurlHandle;
use Monolog\Handler\Curl\Util as CurlUtil;
public function __construct(string $token, array|string $tag = [], $level = Logger::DEBUG, bool $bubble = true)
{
if (!extension_loaded('curl')) {
throw new MissingExtensionException('The curl extension is needed to use the LogglyHandler');
}
$this->token = $token;
if (is_array($tag)) {
$this->tag = $tag;
} else {
$this->tag = [$tag];
}
parent::__construct($level, $bubble);
}
// config/logging.php
'loggly' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => CustomLogglyHandler::class,
'with' => [
'token' => env('LOGGLY_TOKEN'),
'tag' => strtolower(env('APP_NAME', 'Laravel')) . '_' . strtolower(env('APP_ENV', 'production'))
],
],
To expand on Hassan's contribution (posting as an answer, as I still don't have enough reputation to post a comment).
If you have a need to use daily logs locally, you could use following code:
$logFile = 'laravel'.'.txt';
$log->useDailyFiles(storage_path().'/logs/'.$logFile);
Of course, logfile name is totally arbitrary. In this example, format will be as such:
laravel-YYYY-MM-DD.txt
Edit:
with an upgrade to 5.4 this line does not work anymore:
$log = $app->make(Illuminate\Log\Writer::class);
As a workaround, you can create Writer instance manually, injecting $monolog available from configureMonologUsing closure:
$log = new Illuminate\Log\Writer($monolog);