Issue in set monolog in Laravel - laravel

I use this for logging .
I tried to configure log rotation on but I'm stuck. I know how to do this with Laravel, I'm trying to create my own rotating log file in Laravel using Monolog, however, the file rotation is not working and I don't know why.
/* controller file */
use Illuminate\Http\Request;
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
public function getSheduled(){
$log = new Logger('getSheduled');
$log->pushHandler(new RotatingFileHandler(storage_path().'/logs/cron_log/custom_log.log',2, Logger::INFO));
$log->info(json_encode($followup_shedule_data));
}
It seemed pretty straightforward to me, but it's simply not working. The log files are being generated correctly but when When I see their output it give me like this:
/*text file */
[2017-02-14 12:24:46] getSheduled.INFO: [] [] []
I don't want last 2 array from array.Please answer

Change the code as follows:
$lineFormatter = new \Monolog\Formatter\LineFormatter(null, null, true, true);
$log = new Logger('getSheduled');
$log->pushHandler((new RotatingFileHandler(storage_path().'/logs/cron_log/custom_log.log',2, Logger::INFO))->setFormatter($lineFormatter));
$log->info(json_encode($followup_shedule_data));

Related

Laravel: Show output of a console command inside a migration?

I created a command to do some data manipulation on a very large database table and as it takes fair enough time to complete, i took the benefits of progress bar plus echoing some information on the console.
to automate stuff and reduce human errors, i want to call my command inside a laravel migration using programmatically-executing-commands style and it works but the problem is it wont print any output from corresponding command inside the console
i think i should pass the current Output-buffer that artisan:migrate is using to the Artisan::call function to make it work but had no luck to access it inside the migration
any suggestions?
Expanding on #ettdro's answer, the Artisan::call method has the following signature:
Artisan::call(string $command, array $parameters = [], $outputBuffer = null);
As you can see, the method accepts an output buffer as its 3rd argument. You can pass that output buffer to the method and the command logs will show up on the console.
Here's an example:
<?php
use App\Console\Commands\YourConsoleCommand;
use Illuminate\Database\Migrations\Migration;
use Symfony\Component\Console\Output\ConsoleOutput;
class SomeDbMigration extends Migration
{
public function up()
{
$output = new ConsoleOutput();
Artisan::call(YourConsoleCommand::class, ['--some-option' => true], $output);
}
public function down()
{
$output = new ConsoleOutput();
Artisan::call(YourConsoleCommand::class, ['--some-option' => false], $output);
}
}
You could use ConsoleOutput provided by Symfony to print out in the console after calling Artisan command. Make sure to use it in your desired .php file like so use Symfony\Component\Console\Output\ConsoleOutput;.
You could have something like this:
$output = new ConsoleOutput();
$exitCode = Artisan::call('your call');
if ($exitCode == -1)
$output->writeln("<bg=red;options=bold>Error occured while migration rollback " . "Exit code: " . $exitCode ."</>");
else {
$output->writeln("<bg=blue;options=bold>Rollbacked successfully! Exit code: " . $exitCode ."</>");
}
See in my example you can also add colors to your text, that could be useful to have better visuals on errors and success, see more at this link: https://symfony.com/search?q=ConsoleOutput

How to test a route in Laravel that uses both `Storage::put()` and `Storage::temporaryUrl()`?

I have a route in Laravel 7 that saves a file to a S3 disk and returns a temporary URL to it. Simplified the code looks like this:
Storage::disk('s3')->put('image.jpg', $file);
return Storage::disk('s3')->temporaryUrl('image.jpg');
I want to write a test for that route. This is normally straightforward with Laravel. I mock the storage with Storage::fake('s3') and assert the file creation with Storage::disk('s3')->assertExists('image.jpg').
The fake storage does not support Storage::temporaryUrl(). If trying to use that method it throws the following error:
This driver does not support creating temporary URLs.
A common work-a-round is to use Laravel's low level mocking API like this:
Storage::shouldReceive('temporaryUrl')
->once()
->andReturn('http://examples.com/a-temporary-url');
This solution is recommended in a LaraCasts thread and a GitHub issue about that limitation of Storage::fake().
Is there any way I can combine that two approaches to test a route that does both?
I would like to avoid reimplementing Storage::fake(). Also, I would like to avoid adding a check into the production code to not call Storage::temporaryUrl() if the environment is testing. The latter one is another work-a-round proposed in the LaraCasts thread already mentioned above.
I had the same problem and came up with the following solution:
$fakeFilesystem = Storage::fake('somediskname');
$proxyMockedFakeFilesystem = Mockery::mock($fakeFilesystem);
$proxyMockedFakeFilesystem->shouldReceive('temporaryUrl')
->andReturn('http://some-signed-url.test');
Storage::set('somediskname', $proxyMockedFakeFilesystem);
Now Storage::disk('somediskname')->temporaryUrl('somefile.png', now()->addMinutes(20)) returns http://some-signed-url.test and I can actually store files in the temporary filesystem that Storage::fake() provides without any further changes.
Re #abenevaut answer above, and the problems experienced in the comments - the call to Storage::disk() also needs mocking - something like:
Storage::fake('s3');
Storage::shouldReceive('disk')
->andReturn(
new class()
{
public function temporaryUrl($path)
{
return 'https://mock-aws.com/' . $path;
}
}
);
$expectedUrl = Storage::disk('s3')->temporaryUrl(
'some-path',
now()->addMinutes(5)
);
$this->assertEquals('https://mock-aws.com/some-path', $expectedUrl);
You can follow this article https://laravel-news.com/testing-file-uploads-with-laravel, and mix it with your needs like follow; Mocks seem cumulative:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
public function testAvatarUpload()
{
$temporaryUrl = 'http://examples.com/a-temporary-url';
Storage::fake('avatars');
/*
* >>> Your Specific Asserts HERE
*/
Storage::shouldReceive('temporaryUrl')
->once()
->andReturn($temporaryUrl);
$response = $this->json('POST', '/avatar', [
'avatar' => UploadedFile::fake()->image('avatar.jpg')
]);
$this->assertContains($response, $temporaryUrl);
// Assert the file was stored...
Storage::disk('avatars')->assertExists('avatar.jpg');
// Assert a file does not exist...
Storage::disk('avatars')->assertMissing('missing.jpg');
}
}
Another exemple for console feature tests:
command : https://github.com/abenevaut/pokemon-friends.com/blob/1.1.3/app/Console/Commands/PushFileToAwsCommand.php
test : https://github.com/abenevaut/pokemon-friends.com/blob/1.1.6/tests/Feature/Console/Files/PushFileToCloudCommandTest.php

remove request file from laravel request

When I want upload file with form in laravel, I cant remove file value from request.
This is my full code
if($request->hasFile('image')){
$string_name = str_random(12);
$image = $request->file('image')->move(getcwd().'/image/original',$string_name.'.'.$request->file('image')->getClientOriginalExtension());
$request->request->remove('image');
}
if($request->hasFile('thumbnail')){
$string_name = str_random(12);
$thumbnail = $request->file('thumbnail')->move(getcwd().'/image/thumbnail',$string_name.'.'.$request->file('thumbnail')->getClientOriginalExtension());
}
Portfolio::create($request->all());
but image or thumbnail file do not remove from $request. This means this line of code not working :
$request->request->remove('image');
I've tried many ways but the file does not get removed from the request.
Instead of removing the image from your $request before saving, you can explicitly mention what you would like to save to your model by using the ->only([]) method on $request.
Portfolio::create($request->only(['title', ...]));
This will allow you to specify exactly what you would like saved from the $request data.
You can do the reverse and use the ->except() method to remove the image too:
Portfolio::create($request->except('image'));
use this to remove the file
$request->offsetUnset('input_file_name');
or
$request->except('filename');

Laravel 5 log data to another file

Is there any way to log data into another file in laravel 5?
Not to standard one?
For examle i'd like to use something like this:
Log::info("Some log data", '/path/to/custom/file.log');
Or at least is there a possibility to divide log files basing on the log type.
Log::info("Some log data");
Log::error("Another log data");
So that info and error logs will go to different log files.
Thanks for the help.
Here is example:
Log::useFiles(base_path() . '/path/to/custom/file.log', 'info');
Log::info('Do log this another PATH');
Another way
date_default_timezone_set('Asia/Dhaka');
$data = date('Y-m-d');
$time = date('h-A');
Log::useFiles(base_path() . '/log/'.$data.'/'.$time.'-'info.log', 'info');
Log::info('Do log this another PATH');
on this example every date create a folder with saperate log with hourly.
Regarding Laravel 5:
You can also change single log path & name.
Add below line of code to : bootstrap>>app.php very bottom above of return $app;
# SINGLE LOG
$app->configureMonologUsing(function($monolog) use ($app) {
$handler = new Monolog\Handler\StreamHandler($app->storagePath().'/logs/YOUR_SINGLE_LOG_NAME.log');
$handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
$monolog->pushHandler($handler);
});
See https://laravel.com/docs/5.2/errors#configuration specifically Custom Monolog Configuration section.
Follow those directions to override default configuration then following these directions to configure Monolog handlers.
Should be something like:
$app->configureMonologUsing(function($monolog) {
$monolog->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
});
Should get you in the right direction.

Add Custom Variable to Laravel Error Log

I'd like to log the user's name along with the error that is outputted to the log. How do I add a variable to the beginning of an error log entry that outputs an exception?
I think I've got a fairly easy way to do this.
Solution 1
Create a new folder under app called handlers and create a new class called CustomStreamHandler.php which will hold the custom monolog handler.
namespace App\Handlers;
use Monolog\Handler\StreamHandler;
use Auth;
class CustomStreamHandler extends StreamHandler
{
protected function write(array $record)
{
$record['context']['user'] = Auth::check() ? Auth::user()->name : 'guest';
parent::write($record);
}
}
Make sure you set the namespace if you changed it from App and also modify the line where it's setting the user in the context so it works with your users table.
Now we need to drop the current StreamHandler from monolog. Laravel sets this up by default and as far as I can see, there isn't a good way to stop Laravel from doing this.
in app/Providers/AppServiceProvider, we should modify the boot() function to do remove the handler and insert the new one. Add the following...
// Get the underlying instance of monolog
$monolog = \Log::getMonolog();
// Instantiate a new handler.
$customStreamHandler = new \App\Handlers\CustomStreamHandler(storage_path('logs/laravel.log'));
// Set the handlers on monolog. Note this would remove all existing handlers.
$monolog->setHandlers([$customStreamHandler]);
Solution 2
This is a much easier solution but also not exactly what you are looking for (but it might still work for you).
Add the following to AppServiceProvider.php boot().
Log::listen(function()
{
Log::debug('Additional info', ['user' => Auth::check() ? Auth::user()->name : 'guest']);
});
This will simply listen for any logging and also log a debug line containing user information.

Resources