Laravel 5 log data to another file - laravel

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.

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

Issue in set monolog in 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));

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.

How to Remove/Register Suffix on Laravel Route?

EDIT: See below for my current problem. The top portion is a previous issue that I've solved but is somewhat related
I need to modify the input values passed to my controller before it actually gets there. I am building a web app that I want to be able to support multiple request input types (JSON and XML initially). I want to be able to catch the input BEFORE it goes to my restful controller, and modify it into an appropriate StdClass object.
I can't, for the life of me, figure out how to intercept and modify that input. Help?
For example, I'd like to be able to have filters like this:
Route::filter('json', function()
{
//modify input here into common PHP object format
});
Route::filter('xml', function()
{
//modify input here into common PHP object format
});
Route::filter('other', function()
{
//modify input here into common PHP object format
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
Route::when('*.xml', 'xml'); //Any route with '.json' appended uses json filter
Route::when('*.other', 'other'); //Any route with '.json' appended uses json filter
Right now I'm simply doing a Input::isJson() check in my controller function, followed by the code below - note that this is a bit of a simplification of my code.
$data = Input::all();
$objs = array();
foreach($data as $key => $content)
{
$objs[$key] = json_decode($content);
}
EDIT: I've actually solved this, but have another issue now. Here's how I solved it:
Route::filter('json', function()
{
$new_input = array();
if (Input::isJson())
{
foreach(Input::all() as $key => $content)
{
//Do any input modification needed here
//Save it in $new_input
}
Input::replace($new_input);
}
else
{
return "Input provided was not JSON";
}
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
The issue I have now is this: The path that the Router attempts to go to after the filter, contains .json from the input URI. The only option I've seen for solving this is to replace Input::replace($new_input) with
$new_path = str_replace('.json', '', Request::path());
Redirect::to($new_path)->withInput($new_input);
This however leads to 2 issues. Firstly I can't get it to redirect with a POST request - it's always a GET request. Second, the data being passed in is being flashed to the session - I'd rather have it available via the Input class as it would be with Input::replace().
Any suggestions on how to solve this?
I managed to solve the second issue as well - but it involved a lot of extra work and poking around... I'm not sure if it's the best solution, but it allows for suffixing routes similar to how you would prefix them.
Here's the github commit for how I solved it:
https://github.com/pcockwell/AuToDo/commit/dd269e756156f1e316825f4da3bfdd6930bd2e85
In particular, you should be looking at:
app/config/app.php
app/lib/autodo/src/Autodo/Routing/RouteCompiler.php
app/lib/autodo/src/Autodo/Routing/Router.php
app/lib/autodo/src/Autodo/Routing/RoutingServiceProvider.php
app/routes.php
composer.json
After making these modifications, I needed to run composer dumpautoload and php artisan optimize. The rest of those files are just validation for my data models and the result of running those 2 commands.
I didn't split the commit up because I'd been working on it for several hours and just wanted it in.
I'm going to hopefully look to extend the suffix tool to allow an array of suffixes so that any match will proceed. For example,
Route::group(array('suffix' => array('.json', '.xml', 'some_other_url_suffix')), function()
{
// Controller for base API function.
Route::controller('api', 'ApiController');
});
And this would ideally accept any call matching
{base_url}/api/{method}{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?}{suffix}`
Where:
base_url is the domain base url
method is a function defined in ApiController
{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?} is a series of up to 5 optional variables as are added when registering a controller with Route::controller()
suffix is one of the values in the suffix array passed to Route::group()
This example in particular should accept all of the following (assuming localhost is the base url, and the methods available are getMethod1($str1 = null, $str2 = null) and postMethod2()):
GET request to localhost/api/method1.json
GET request to localhost/api/method1.xml
GET request to localhost/api/method1some_other_url_suffix
POST request to localhost/api/method2.json
POST request to localhost/api/method2.xml
POST request to localhost/api/method2some_other_url_suffix
GET request to localhost/api/method1/hello/world.json
GET request to localhost/api/method1/hello/world.xml
GET request to localhost/api/method1/hello/worldsome_other_url_suffix
The last three requests would pass $str1 = 'hello' and $str2 = 'world' to getMethod1 as parameters.
EDIT: The changes to allow multiple suffixes was fairly easy. Commit located below (please make sure you get BOTH commit changes to get this working):
https://github.com/pcockwell/AuToDo/commit/864187981a436b60868aa420f7d212aaff1d3dfe
Eventually, I'm also hoping to submit this to the laravel/framework project.

Laravel 4 SQL log / console

Is there something similar in Laravel that allows you to see the actual SQL being executed?
In Rails, for example, you can see the SQL in console. In Django you have a toolbar.
Is there something like that in Laravel 4?
To clarify: My question is how to do it without code. Is there something that is built-in in Laravel that does not require me to write code in app?
UPDATE: Preferably I'd like to see CLI queries as well (for example php artisan migrate)
If you are using Laravel 4, use this:
$queries = DB::getQueryLog();
$last_query = end($queries);
I do this in Laravel 4.
Just set it once in app/start/global.php or anywhere but make sure it is loaded and then it will start logging all your SQL queries.
Event::listen("illuminate.query", function($query, $bindings, $time, $name){
\Log::sql($query."\n");
\Log::sql(json_encode($bindings)."\n");
});
Here is a quick Javascript snippet you can throw onto your master page template.
As long as it's included, all queries will be output to your browser's Javascript Console.
It prints them in an easily readable list, making it simple to browse around your site and see what queries are executing on each page.
When you're done debugging, just remove it from your template.
<script type="text/javascript">
var queries = {{ json_encode(DB::getQueryLog()) }};
console.log('/****************************** Database Queries ******************************/');
console.log(' ');
$.each(queries, function(id, query) {
console.log(' ' + query.time + ' | ' + query.query + ' | ' + query.bindings[0]);
});
console.log(' ');
console.log('/****************************** End Queries ***********************************/');
</script>
There is a Composer package for that: https://packagist.org/packages/loic-sharma/profiler
It will give you a toolbar at the bottom with SQL queries, log messages, etc. Make sure you set debug to true in your configuration.
Here's another nice debugging option for Laravel 4:
https://github.com/barryvdh/laravel-debugbar
I came up with a really simple way (if you are using php artisan serve and PHP 5.4) - add this to app/start/local.php:
DB::listen(function($sql, $bindings, $time)
{
file_put_contents('php://stderr', "[SQL] {$sql} in {$time} s\n" .
" bindinds: ".json_encode($bindings)."\n");
});
but hoping to find a more official solution.
This will print SQL statements like this:
[SQL] select 1 in 0.06s
This code is directly taken form other source but i wanted to make it easy for you as follow it worked for me on PHPStorm using my terminal window i was able to see a complete log but ,after login there was some Sentry thing.
1.add
'log'=>true
inside your config/database.php and below the place ur database name ex.mysql
then add below code toroutes.php above all no under any route configuration , since u can make that under a give route configuration but , u only see when that route is called.
to see this output /goto / app/storage/log/somelogfile.log
if (Config::get('database.log', false))
{
Event::listen('illuminate.query', function($query, $bindings, $time, $name)
{
$data = compact('bindings', 'time', 'name');
// Format binding data for sql insertion
foreach ($bindings as $i => $binding)
{
if ($binding instanceof \DateTime)
{
$bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
}
else if (is_string($binding))
{
$bindings[$i] = "'$binding'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
Log::info($query, $data);
});
}
Dont forget to make break point .... or ping me :)
In QueryBuilder instance there is a method toSql().
echo DB::table('employees')->toSql()
would return:
select * from `employees`
This is the easiest method to shows the queries.

Resources