-
Notifications
You must be signed in to change notification settings - Fork 327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PSR-3 compliance #563
PSR-3 compliance #563
Conversation
a3eed3e
to
b7d0fea
Compare
Hmm, this is not based on 3.4/develop. It seems to me that I have created a branch starting from the wrong revision. |
Or maybe I did not pull before starting. |
@acoulton, could you kindly review this? Also, kindly guide me what types of tests I need to write to make this complete? |
This is freking great, I'm very glad to see Kohana move closer to full PSR :) 👍 |
@enov this is looking great. A couple of thoughts:
In terms of testing, things I'd consider covering (I've not reviewed what if anything is covered by existing tests): Kohana_Core::init
Kohana_Exception::log
Kohana_Log
Kohana_Log_Syslog
And if Kohana_Log_Writer::format_message doesn't already have coverage then I guess also tests for that. |
No we don't, interfaces should not be transparently extended like implementations, IMHO.
My initial intention was to be psr-3 compliant with the least change possible in the code base. I thought can further enhance the code in later versions. What do you say? |
Agreed - but you have both in this PR. My preference would be to drop
Fair point, yes this pull should be limited to what's strictly necessary for PSR3. |
Agreed. I will create an issue for this later, targeting all other interfaces that follow this pattern. |
@enov do you think PSR-7 http-message should be implemented as well? |
@arteymix that's still under discussion. Plus, it would require us to be PSR-1/2 coding style, because unlike this PSR-3, it has long camelCased method names. There is also a draft RFC about HTTP interface, that might go into PHP 7: |
That's what I feared when I looked into the specification. PSR 1/2 is hardly thinkable at thins point. It's a good thing though that we get more compliance with PSR, so I second you on that PR. |
@acoulton, I am struggling with writing the first test:
The problem is that PHPUnit boostraps Kohana the standard way, which calls So, since It seems to me I am hunting some kind of chicken and egg problem. I found the following 2 sub-par solutions: Solution 1: Replay parts of bootstrap within the testTo be able to Kindly find here-under the code for this solution: /**
* Tests Kohana::init() for default log file creation
*/
public function test_init_creates_default_log_instance_if_not_set()
{
// de-initialize Kohana, should set Kohana::$log to NULL
Kohana::deinit();
// re-register autoloader as de-initialization removes that
spl_autoload_register(array('Kohana', 'auto_load'));
// test if Kohana::$log is NULL at this point
$this->assertNull(Kohana::$log);
// re-initialize Kohana
Kohana::init();
// test if a default log instance is created
$this->assertInstanceOf('Log', Kohana::$log);
/**
* At this point we need to replay some part from bootstrap
* so that other tests may continue normally
*/
// Attach the file write to logging. Multiple writers are supported.
Kohana::$log->attach(new Log_File(APPPATH . 'logs'));
//Attach a file reader to config. Multiple readers are supported.
Kohana::$config->attach(new Config_File);
} Solution 2: a TestableCore that extends Core with a public set_init_flagThis solution relies on the fact that we can run Please see the code for this solution here: /**
* Tests Kohana::init() for default log file creation
*/
public function test_init_creates_default_log_instance_if_not_set()
{
// set $log to NULL, as it inherited the instance from the parent class
Kohana_CoreTest_TestableCore::$log = NULL;
// test if it is NULL (do we need this?)
$this->assertNull(Kohana_CoreTest_TestableCore::$log);
// set the flag Kohana::$_init to FALSE to be able to run init() again
Kohana_CoreTest_TestableCore::set_init_flag(FALSE);
// initialize Kohana again
Kohana_CoreTest_TestableCore::init();
// assert
$this->assertInstanceOf('Log', Kohana_CoreTest_TestableCore::$log);
} Code for class Kohana_CoreTest_TestableCore extends Kohana_Core {
/**
* Sets the init flag to force initialization/deinitialization
* @param bool $flag
*/
public static function set_init_flag($flag)
{
static::$_init = $flag;
}
} Thanks. |
@enov yes, that's all fairly horrid isn't it :) Not sure what to suggest, as you say the main issue is that I suppose you could split all the separate actions in init into protected methods, then stub a class that makes all of them no-op - for example: class Kohana_Core {
public static function init() {
if (Kohana::$_init)
{
// Do not allow execution twice
return;
}
// Kohana is now initialized
Kohana::$_init = TRUE;
static::init_profile();
static::init_errors();
static::init_shutdown();
static::init_windows();
static::init_cache();
// etc
static::init_log();
static::init_config();
}
}
class LogInitKohana_CoreStub extends Kohana_Core {
public static function init()
{
self::$_init = FALSE;
}
public static function init_profile() {}
public static function init_errors() {}
public static function init_cache() {}
// etc for everything except init_log
} That's not very nice either because of the need to be sure every Another option would be to break the init method up into a stack of initialisers (classes or callables of some kind) - then you could just test the LogInitialiser. That would be cleaner and give more scope for extension in future and by end-users, but is obviously a chunky refactoring and may have performance, BC and other considerations. Maybe for now the only sensible thing in the current architecture is to assume that PHPUnit didn't itself assign anything to |
If we can get away with that for the first test, we can not for the second test you suggested 😄
|
@enov indeed. I think maybe we have to accept that's almost impossible to test without introducing a lot of changes that aren't directly relevant to this PR. The only other thing I thought of was shelling out to a script in a separate PHP process but that would be pretty unpleasant too. Maybe for now these are things that just have to be verified by eye/knowing they work in end-user apps. |
c590c41
to
015a164
Compare
I added tests comparing messages resulting from the generic Tests are currently failing. This is because PSR-3 specifies that:
I think we either need to normalize the trace entries, by carefully re-engineering the result of the call to debug_backtrace, or to forget about the trace entry, as it is ignored by the abstract For the record, the file, line, class, and function entries are also giving different results. Sometimes they are Any insight and guidance is greatly appreciated. |
Alright, played with fire and removed trace, class, and function keys from log message. Please review. cc @acoulton, @lenton, @rjd22, @shadowhand |
Do not merge yet. |
@acoulton I know you might be busy, but I just need your confirmation in case we can get rid of trace, class, and function from log message (as we are not using them in the default log writer). Those are still available in case of an exception. I'll write more tests to prove the case. |
@enov so sorry, I've been flat out. I've just had a quick look over this and it's looking good. I think it's fine to drop trace, class and function from ordinary log messages - as you say they're not written by any of our own writers and anyway that feels like something where the end-user should pass them as part of the context if they want them. Apart from unexpected exceptions (which are handled separately) usually you know the trace of application-specific logs. |
Thanks for the review @acoulton . |
Thanks for the review @rjd22. |
@enov any updates on this? |
$write_levels is now an array of all levels with the key as the level and a boolean value TRUE when the level is writable.
`Log_Writer::get_psr_write_levels_map()`: Gets an array mapping PSR levels to boolean values with TRUE indicating that the level at the key is writable `Log_Writer::get_psr_write_levels`: Gets the PSR log levels that this writer accepts to write `Log_Writer::get_int_write_levels`: Gets the integer log levels that this writer accepts to write
- Symmetric getters/setters, get what you set - Simplified variable and methods naming - Throws InvalidArgumentException when setting duplicate levels - Remove filtering in range, easily achievable in userland
In a pattern similar to attaching Log_Writer(s) to the Log, we can now attach log filters to the writers. Add Log_Filter_PSRLevel to filter logs by PSR levels.
Windows users see PHP Bug #18090 Add this note in the Syslog writer as well.
In Log_File, removed the conversion to `realpath` when storing the log directory, as it is incompatible with streams.
8f3cebe
to
304678d
Compare
Thanks for reviewing again, @acoulton. Yeah, it built normally after I restarted it, most probably Travis/HHVM issue. |
Adopt PSR-3 compatible logger and refactor logging implementation See updated userguide and upgrading guide.
@enov 🍻 🍰 🎈 🎆 and general 🎉 Thanks very much for this! |
@enov Thanks a log for the hard work!! |
This is a work-in-progress for PSR-3 compliance.