
Berapa kali Anda menulis logger.info('ServiceName.methodName.')
Dan logger.info('ServiceName.methodName -> done.')
Untuk setiap dan setiap metode layanan Anda yang ingin Anda log? Apakah Anda ingin otomatis dan memiliki tanda tangan konstan yang sama di seluruh aplikasi Anda? Jika begitu, kita sangat mirip, kita telah menderita rasa sakit yang sama terlalu sering, dan sekarang kita akhirnya bisa mencoba mengatasinya. Bersama. Hadirin sekalian, izinkan saya memperkenalkan ... penebang kelas !
Insinyur sering perfeksionis. Perfeksionis sampai ekstrem. Kami menyukai abstraksi yang rapi. Kami suka kode bersih. Kami melihat keindahan dalam bahasa buatan yang bahkan orang lain tidak bisa baca. Kami menyukai pembuatan alam semesta digital kecil, hidup dengan aturan yang kami tetapkan. Kami menyukai semua itu, mungkin, karena kami sangat malas. Tidak, kami tidak takut bekerja, tetapi kami benci melakukan pekerjaan apa pun yang dapat diotomatisasi.
Setelah menulis beberapa ribu baris hanya kode logging, kami biasanya datang dengan pola-pola tertentu, menstandarisasi apa yang ingin kita catat. Namun kita masih harus menerapkan pola itu secara manual. Jadi ide inti class-logger adalah untuk menyediakan cara standar deklaratif yang sangat dapat dikonfigurasi untuk mencatat pesan sebelum dan sesudah eksekusi metode kelas.
Mulai cepat
Mari kita mulai bekerja dan melihat seperti apa kode yang sebenarnya.
import { LogClass, Log } from 'class-logger' @LogClass() class ServiceCats { @Log() eat(food: string) { return 'purr' } }
Layanan ini akan masuk tiga kali:
- Pada saat penciptaannya dengan daftar argumen diteruskan ke konstruktor.
- Sebelum
eat
dijalankan dengan daftar argumennya. - Setelah
eat
dieksekusi dengan daftar argumen dan hasilnya.
Dalam kata-kata kode:
// Logs before the actual call to the constructor // `ServiceCats.construct. Args: [].` const serviceCats = new ServiceCats() // Logs before the actual call to `eat` // `ServiceCats.eat. Args: [milk].` serviceCats.eat('milk') // Logs after the actual call to `eat` // `ServiceCats.eat -> done. Args: [milk]. Res: purr.`
Demo langsung .
Apa lagi yang bisa kita login? Berikut daftar lengkap acara:
- Sebelum konstruksi kelas.
- Sebelum metode statis dan non-statis sinkron dan asinkron dan sifat fungsional.
- Setelah metode statis dan non-statis sinkron dan asinkron dan sifat fungsional.
- Kesalahan metode statis dan non-statis sinkron dan asinkron serta sifat fungsional.
Properti fungsional adalah fungsi panah yang ditetapkan ke properti ( class ServiceCats { private meow = () => null }
).
Menyesuaikannya dengan kebutuhan kita
Sejauh ini bagus, tapi kami telah dijanjikan "dapat disesuaikan", bukan? Jadi bagaimana kita bisa mengubahnya?
class-logger menyediakan tiga lapisan konfigurasi hirarkis:
Pada setiap pemanggilan metode, ketiganya dievaluasi dan digabungkan bersama dari atas ke bawah. Ada beberapa konfigurasi global default yang waras, sehingga Anda dapat menggunakan perpustakaan tanpa konfigurasi sama sekali.
Konfigurasi global
Ini adalah konfigurasi aplikasi-lebar. Dapat diatur dengan panggilan setConfig
.
import { setConfig } from 'class-logger' setConfig({ log: console.info, })
Konfigurasi kelas
Ini memiliki efek terhadap setiap metode kelas Anda. Itu bisa mengesampingkan konfigurasi global.
import { LogClass } from 'class-logger' setConfig({ log: console.info, }) @LogClass({ // It overrides global config for this service log: console.debug, }) class ServiceCats {}
Konfigurasi metode
Itu hanya mempengaruhi metode itu sendiri. Mengganti konfigurasi kelas dan, karenanya, konfigurasi global.
import { LogClass } from 'class-logger' setConfig({ log: console.info, }) @LogClass({ // It overrides global config for this service log: console.debug, }) class ServiceCats { private energy = 100 @Log({ // It overrides class config for this method only log: console.warn, }) eat(food: string) { return 'purr' } // This method stil uses `console.debug` provided by class config sleep() { this.energy += 100 } }
Demo langsung
Opsi konfigurasi
Yah, kita sudah belajar cara mengubah default, namun tidak ada salahnya untuk menutupi apa yang ada untuk mengkonfigurasi, ya?
Di sini Anda dapat menemukan banyak override konfigurasi yang berguna .
Inilah tautan ke antarmuka objek config jika Anda dapat menggunakan TypeScript lebih baik daripada bahasa Inggris :)
Objek konfigurasi memiliki properti ini:
log
Ini adalah fungsi yang melakukan pencatatan aktual pesan akhir yang diformat. Ini digunakan untuk mencatat peristiwa ini:
- Sebelum konstruksi kelas.
- Sebelum metode statis dan non-statis sinkron dan asinkron dan sifat fungsional.
- Setelah metode statis dan non-statis sinkron dan asinkron dan sifat fungsional.
Default: console.log
logError
Ini adalah fungsi yang melakukan pencatatan aktual dari pesan kesalahan yang diformat akhir. Ini digunakan untuk mencatat peristiwa ini dan satu-satunya:
- Kesalahan metode statis dan non-statis sinkron dan asinkron serta sifat fungsional.
Default: console.error
Ini objek dengan dua metode: start
dan end
. Ini memformat data logging ke string terakhir.
start
format pesan untuk acara ini:
- Sebelum konstruksi kelas.
- Sebelum metode statis dan non-statis sinkron dan asinkron dan sifat fungsional.
end
format pesan untuk acara ini:
- Setelah metode statis dan non-statis sinkron dan asinkron dan sifat fungsional.
- Kesalahan metode statis dan non-statis sinkron dan asinkron serta sifat fungsional.
Default: new ClassLoggerFormatterService()
termasuk
Konfigurasi apa yang harus dimasukkan dalam pesan.
args
Itu bisa berupa boolean atau objek.
Jika boolean, itu menetapkan apakah akan menyertakan daftar argumen (ingat bahwa Args: [milk]
?) Ke keduanya, mulai (sebelum konstruksi dan sebelum panggilan metode) dan berakhir (setelah panggilan metode, panggilan metode kesalahan), pesan.
Jika itu sebuah objek, ia harus memiliki dua properti boolean: start
dan end
. start
termasuk / tidak termasuk daftar argumen untuk pesan awal, end
melakukan hal yang sama untuk pesan akhir.
Default: true
membangun
Pengaturan boolean flag apakah akan mencatat konstruksi kelas atau tidak.
Default: true
hasil
Pengaturan boolean flag lain apakah akan memasukkan nilai balik dari pemanggilan metode atau kesalahan yang dilemparkan olehnya. Ingat Res: purr
? Jika Anda menetapkan bendera ini ke false
tidak akan ada Res: purr
.
Default: true
kelasInstance
Sekali lagi, baik boolean atau objek.
Jika Anda mengaktifkannya, representasi string instance kelas Anda akan ditambahkan ke log. Dengan kata lain, jika instance kelas Anda memiliki beberapa properti, mereka akan dikonversi ke string JSON dan ditambahkan ke pesan log.
Tidak semua properti akan ditambahkan. class-logger mengikuti logika ini:
- Ambil properti sendiri (non-prototipe) dari sebuah instance.
- Mengapa Ini adalah kasus yang jarang terjadi ketika prototipe Anda berubah secara dinamis, oleh karena itu hampir tidak masuk akal untuk mencatatnya.
- Jatuhkan salah satu dari mereka yang memiliki tipe
function
.
- Mengapa Sebagian besar properti
function
waktu hanyalah fungsi panah tetap yang digunakan alih-alih metode kelas biasa untuk mempertahankan konteks this
. Tidak masuk akal untuk menggembungkan log Anda dengan tubuh yang dirubah dari fungsi-fungsi itu.
- Jatuhkan salah satu dari mereka yang bukan benda biasa.
- Benda apa yang polos?
ClassLoggerFormatterService
menganggap suatu objek objek sederhana jika prototipe-nya benar-benar sama dengan Object.prototype
. - Mengapa Seringkali kita memasukkan instance dari kelas lain sebagai properti (menyuntikkannya sebagai dependensi). Log kami akan menjadi sangat gemuk jika kami menyertakan versi ketat dari dependensi ini.
- Tentukan apa yang tersisa.
class ServiceA {} @LogClass({ include: { classInstance: true, }, }) class Test { private serviceA = new ServiceA() private prop1 = 42 private prop2 = { test: 42 } private method1 = () => null @Log() public method2() { return 42 } } // Logs to the console before the class' construction: // 'Test.construct. Args: []. Class instance: {"prop1":42,"prop2":{"test":42}}.' const test = new Test() // Logs to the console before the method call: // 'Test.method2. Args: []. Class instance: {"prop1":42,"prop2":{"test":42}}.' test.method2() // Logs to the console after the method call: // 'Test.method2 -> done. Args: []. Class instance: {"prop1":42,"prop2":{"test":42}}. Res: 42.'
Default: false
Jadi bagaimana jika Anda menyukai ide keseluruhan, tetapi ingin pesan Anda terlihat berbeda? Anda dapat mengambil kendali penuh atas pemformatan yang melewati pemformat kustom Anda sendiri.
Anda dapat menulis formatter Anda sendiri dari awal. Benar-benar Namun kami tidak akan membahas opsi ini di sini (jika Anda benar-benar tertarik dengan itu, alamat bagian "Memformat" dari README).
Yang tercepat dan, mungkin, hal termudah untuk dilakukan adalah dengan subkelas pemformat bawaan bawaan - ClassLoggerFormatterService
.
ClassLoggerFormatterService
memiliki metode yang dilindungi ini, berfungsi sebagai blok bangunan pesan terakhir:
base
- Mengembalikan nama kelas dengan nama metode. Contoh:
ServiceCats.eat
.
operation
- Mengembalikan
-> done
atau -> error
berdasarkan apakah itu merupakan eksekusi yang sukses dari suatu metode atau yang salah.
args
- Mengembalikan daftar argumen yang dirubah. Contoh :.
. Args: [milk]
. Ini menggunakan fast-safe-stringify untuk objek di bawah tenda.
classInstance
- Mengembalikan turunan kelas stringified. Contoh :.
. Class instance: {"prop1":42,"prop2":{"test":42}}
. Jika Anda memilih untuk memasukkan instance kelas, tetapi itu tidak tersedia (begitulah metode statis dan konstruksi kelas), ia mengembalikan N/A
result
- Mengembalikan hasil eksekusi yang diketik (bahkan jika itu adalah kesalahan). Menggunakan fast-safe-stringify untuk membuat serialisasi objek. Kesalahan yang terkomplikasi akan terdiri dari properti berikut:
- Nama kelas (fungsi) kesalahan dibuat dengan (
error.constructor.name
). - Kode kesalahan (
error.code
). - Pesan kesalahan (
error.message
). - Nama kesalahan (
error.name
). - Jejak tumpukan (
error.stack
).
final
Pesan start
terdiri dari:
base
args
classInstance
final
Pesan end
terdiri dari:
base
operation
args
classInstance
result
final
Anda bisa mengesampingkan salah satu metode blok bangunan tersebut. Mari kita lihat bagaimana kita bisa menambahkan stempel waktu. Saya tidak mengatakan kita harus melakukannya. pino , winston dan banyak penebang lainnya mampu menambahkan cap waktu sendiri. Jadi contohnya adalah murni mendidik.
import { ClassLoggerFormatterService, IClassLoggerFormatterStartData, setConfig, } from 'class-logger' class ClassLoggerTimestampFormatterService extends ClassLoggerFormatterService { protected base(data: IClassLoggerFormatterStartData) { const baseSuper = super.base(data) const timestamp = Date.now() const baseWithTimestamp = `${timestamp}:${baseSuper}` return baseWithTimestamp } } setConfig({ formatter: new ClassLoggerTimestampFormatterService(), })
Demo langsung
Kesimpulan
Tolong, jangan lupa untuk mengikuti langkah - langkah instalasi dan berkenalan dengan persyaratan sebelum Anda memutuskan untuk menggunakan perpustakaan ini.
Semoga Anda menemukan sesuatu yang berguna untuk proyek Anda. Silakan sampaikan umpan balik Anda kepada saya! Saya sangat menghargai kritik dan pertanyaan apa pun.