Üretim kodunda NSLog () kullanılmaması gerektiği doğru mu?


155

Bu sitede bu birkaç kez söylendi, ama bunun gerçekten böyle olduğundan emin olmak istedim.

Kodum boyunca NSLog işlev çağrıları serpiştirmeyi bekliyordum ve Xcode / gcc, Release / Distribution sürümlerimi oluştururken bu çağrıları otomatik olarak çıkarırdı.

Bunu kullanmaktan kaçınmalı mıyım? Öyleyse, deneyimli Objective-C programcıları arasında en yaygın olan alternatifler nelerdir?


7
Bu sorunun artık çok eski olduğunu biliyorum, ama hala yapabiliyorsanız, Marc Charbonneau'nun cevabını kabul edilmiş olarak işaretlerdim. Cevabımı ona işaret edecek şekilde değiştirdim, ama cevabı doğru.
e.James

5
Sık sık bir döngü içinde NSLog () kesinlikle performansınızı öldürecek, dedi zor yoldan öğrendim.
willc2

Yanıtlar:


197

Önişlemci makroları hata ayıklama için gerçekten harikadır. NSLog () ile ilgili yanlış bir şey yoktur, ancak kendi günlük kayıt işlevinizi daha iyi işlevlerle tanımlamak basittir. İşte kullandığım, günlük deyimlerini izlemeyi kolaylaştırmak için dosya adını ve satır numarasını içerir.

#define DEBUG_MODE

#ifdef DEBUG_MODE
    #define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
    #define DebugLog( s, ... ) 
#endif

Bu ifadeyi kendi dosyasından ziyade önek başlığına koymayı daha kolay buldum. İsterseniz DebugLog'un normal Objective-C nesneleriyle etkileşime girmesini sağlayarak daha karmaşık bir günlük sistemi oluşturabilirsiniz. Örneğin, kendi günlük dosyasına (veya veritabanına) yazan ve çalışma zamanında ayarlayabileceğiniz bir 'öncelik' bağımsız değişkeni içeren bir günlük sınıfınız olabilir, bu nedenle hata ayıklama iletileri sürümünüzde gösterilmez, ancak hata iletileri ( bunu yaptıysanız, DebugLog (), WarningLog () vb.) yapabilirsiniz.

Oh, ve aklınızda bulundurun #define DEBUG_MODEuygulamanızda farklı yerlerde yeniden kullanılabilir. Örneğin, uygulamamda lisans anahtarı denetimlerini devre dışı bırakmak ve yalnızca belirli bir tarihten önce çalışmasına izin vermek için kullanıyorum. Bu, benim için çok az çaba harcayarak zaman sınırlı, tamamen işlevsel bir beta kopya dağıtmamı sağlıyor.


8
Mükemmel bir cevap için +1. Benim #define makroları gitmek için yol olduğunu belirtmek için benim değiştirdim ve umarım OP kabul edilen cevap değiştirir (Ona bir yorum yaptı). Bir makroda ... argümanlar kullanabileceğinizi bilmediğim için kukla bir işlev kullanıyordum. Yaşamayı öğren!
e.James

15
Mükemmel bir cevap, "DEBUG_MODE" tanımınızda, "JPM_DEBUG" veya benzeri adlandırma gibi kişisel bir önek kullanmanızı öneririm. Çok sık DEBUG veya DEBUG_MODE veya benzerlerini kullanan üçüncü taraf koduyla karşılaştım ve bazen bu kod DEBUG modunda düzgün çalışmaz. Üçüncü taraf kütüphane hata ayıklamasını açmak istiyorsanız bunu kasıtlı olarak yapmanız gerekir. (Tabii ki, sembollerini önek olarak kullanması gereken kütüphane yazarlarıdır, ancak birçok C ve C ++ çerçevesi özellikle bu tanım için değildir).
Rob Napier

1
yalnızca yapılandırma hata ayıklamaya ayarlandığında bunu açmak için kullanılabilecek önceden tanımlanmış bir Xcode makro var mı? Bu önişlemci makrosunu her projede kendim manuel olarak ayarlamayı tercih etmiyorum. XCODE_CONFIGURATION == DEBUG pseudocode #if'i takip etmek gibi bir şey yapabilir miyiz?
frankodwyer

1
#include <TargetConditionals.h>
slf

2
Bu yaklaşım, günlüğe kaydetme ifadeleri yalnızca günlüğe kaydedilecek değerleri hesaplamak amacıyla ara değişkenler kullandığında derleyiciden yayımlanan "kullanılmayan değişkenler" uyarılarına yol açar. Derleyici uyarılarından benim kadar nefret ederseniz bundan kaçınmanın en akıllı yolu ne olurdu?
Jean-Denis Muys

78

Bu 3 satırı -prefix.pch dosyasının sonuna yerleştirin:

#ifndef DEBUG
  #define NSLog(...) /* suppress NSLog when in release mode */
#endif

Projenize herhangi bir şey tanımlamanız gerekmez, çünkü DEBUGprojenizi oluştururken varsayılan olarak oluşturma ayarınızda tanımlanır.


2
En iyi çözüm. XCode 6'dan elle prefix.pch eklemeniz gerekiyor.
Teddy

Yine de sürüm ayarını sürümden önce değiştirmemiz gerekiyor mu yani sürümden
çıkmak

25

NSLog çağrıları üretim kodunda bırakılabilir, ancak yalnızca gerçekten istisnai durumlar veya sistem günlüğüne kaydedilecek istenen bilgiler için orada olmalıdır.

Sistem günlüğünü kirleten uygulamalar sinir bozucu ve profesyonel olmayan olarak karşımıza çıkıyor.


14
Özür dilerim - kimin için profesyonel değil? Yayınlanan bir uygulamada günlüklerinizi kim kontrol ediyor ve profesyonelliğinizi buna göre değerlendiriyor? (Açık olmak gerekirse, başvurunuzun yayın sürümünde bir ton NSLogs tutmamanız gerektiğine tamamen katılıyorum, ancak 'profesyonellik' argümanı ile kafam karıştı.)
WendiKidd

4
Diğer geliştiriciler yaptığını yapacak ve sinirlenecek. Android, bazı geliştiricilerin gerçekten kötü olması ile benzer bir sorunu var plus.google.com/110166527124367568225/posts/h4jK38n4XYR
Roger Binns

24

Marc Charbonneau'nun cevabı hakkında yorum yapamam , bu yüzden bunu cevap olarak göndereceğim.

Makroyu önceden derlenmiş başlığınıza eklemek için, hedef oluşturma yapılandırmalarını kullanarak tanımlamayı (veya tanımlamamayı) kontrol edebilirsiniz DEBUG_MODE.

" Hata ayıkla " seçeneğini belirlerseniz , etkin yapılandırma DEBUG_MODEtanımlanır ve makro tam NSLogtanıma genişler .

" Release " aktif konfigürasyonunun seçilmesi tanımlanmayacaktır DEBUG_MODEve NSLogging'iniz release derlemesinden çıkarılmıştır.

Adımlar:

  • Hedef> Bilgi Al
  • Derleme sekmesi
  • "Önişlemci Makroları" (veya GCC_PREPROCESSOR_DEFINITIONS) için arama yapın
  • Yapılandırma Seçin: Hata ayıklama
  • Bu Düzeydeki Tanımı Düzenle
  • Ekle DEBUG_MODE=1
  • Yapılandırma Seçin: Sürüm
  • onayla DEBUG_MODEiçinde ayarlı değilGCC_PREPROCESSOR_DEFINITIONS

tanımdaki '=' karakterini atlarsanız, önişlemciden bir hata alırsınız

Ayrıca, tanımın nereden DEBUG_MACROgeldiğini hatırlatmak için bu yorumu (aşağıda gösterilmiştir) makro tanımının üstüne yapıştırın ;)

// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
//               = Debug:   DEBUG_MODE=1

1
Bu soruya değerli bir ek cevap. Bir yorumdan daha fazlasını hak ediyor.
morningstar

DEBUG_MODEve DEBUG_MACROalışılmadık. Apple'ınDEBUG_MACRO sitesinde yalnızca bir referans buldum ( opensource.apple.com/source/gm4/gm4-15/src/m4.h?txt ). Belki daha standart DEBUGve NDEBUGdaha iyi seçimler olurdu? NDEBUGPosix ile belirtilir; ise DEBUGgeleneksel olarak kullanılır.
jww

+1 Evet bu eski bir gönderi, ama mesele şu ki ... Xcode sürümümde (4 yıl sonra), GCC_PREPROCESSOR_DEFINITIONS araması farklı bir dil döndürüyor. Lütfen netlik için bu mükemmel cevabı güncelleyin.
David

11

DÜZENLEME: metot tarafından gönderildi Marc Charbonneau ve tarafından dikkatimi çekti sho , çok daha iyi bu bir fazla.

Yanıtımın hata ayıklama modu devre dışı bırakıldığında günlüğü devre dışı bırakmak için boş bir işlev kullanılmasını öneren bölümünü sildim. Otomatik önişlemci makrosunun ayarlanmasıyla ilgilenen kısım hala geçerlidir, bu yüzden kalır. Ayrıca önişlemci makrosunun adını da düzenledim, böylece Marc Charbonneau'nun cevabına daha iyi uyuyor.


Xcode'da otomatik (ve beklenen) davranışı elde etmek için:

Proje ayarlarında "Derleme" sekmesine gidin ve "Hata Ayıkla" yapılandırmasını seçin. "Önişlemci Makroları" bölümünü bulun ve adlı bir makro ekleyin DEBUG_MODE.

...

DÜZENLEME: Makro ile günlük kaydını etkinleştirmek ve devre dışı bırakmak için Marc Charbonneau'nun yanıtına bakın DEBUG_MODE.


7

Matthew ile aynı fikirdeyim. Üretim kodunda NSLog ile ilgili yanlış bir şey yok. Aslında, kullanıcı için yararlı olabilir. Bununla birlikte, NSLog'u kullanmanın tek nedeni hata ayıklamaya yardımcı olmaksa, evet, serbest bırakmadan önce kaldırılması gerekir.

Dahası, bunu bir iPhone sorusu olarak etiketlediğiniz için NSLog, iPhone'un çok az değerli olduğu bir şey olan kaynakları alıyor. Ediyoruz NSLogging Eğer varsa her şey uygulamadan gelen işlemci zamanını alır götürür iPhone'da. Akıllıca kullanın.


4

Basit gerçek şu ki NSLog sadece yavaş.

Ama neden? Bu soruyu cevaplamak için NSLog'un ne yaptığını ve sonra nasıl yaptığını bulalım.

NSLog tam olarak ne yapıyor?

NSLog 2 şey yapar:

Günlük sistemlerini Apple Sistem Günlüğü (asl) tesisine yazar. Bu, günlük iletilerinin Console.app içinde görünmesini sağlar. Ayrıca, uygulamanın stderr akışının bir terminale gidip gitmediğini de kontrol eder (örneğin, uygulamanın Xcode ile çalıştırıldığı gibi). Öyleyse, günlük iletisini stderr'a yazar (böylece Xcode konsolunda görünür).

STDERR'a yazmak zor görünmüyor. Bu fprintf ve stderr dosya tanımlayıcı referansı ile gerçekleştirilebilir. Peki ya asl?

ASL hakkında bulduğum en iyi belgeler Peter Hosey'den 10 bölümlük bir blog yazısı: link

Çok fazla ayrıntıya girmeden, vurgu (performansla ilgili olarak) şudur:

ASL tesisine bir günlük mesajı göndermek için, temel olarak ASL arka plan programına bir istemci bağlantısı açar ve mesajı gönderirsiniz. AMA - her iş parçacığının ayrı bir istemci bağlantısı kullanması gerekir. Bu nedenle, iş parçacığı güvenli olmak için, NSLog her çağrıldığında yeni bir asl istemci bağlantısı açar, iletiyi gönderir ve sonra bağlantıyı kapatır.

Kaynaklar burada ve burada bulunabilir .


Metni düzenledi. Kaynakların yalnızca altbilgide olması gerekir.
Johan Karlsson

2

Diğer yanıtlarda belirtildiği gibi NSLog'un derleme zamanında kullanılıp kullanılmadığını değiştirmek için #define kullanabilirsiniz.

Bununla birlikte, daha esnek bir yol, Cocoa Lumberjack gibi bir günlük kütüphanesi kullanmaktır .

Kodunuzda NSLog yerine DDLogVerbose veya DDLogError vb. Yazın, makro tanımları vb. İçin bir #import ekleyin ve günlükleri genellikle applicationDidFinishLaunching yönteminde ayarlayın.

NSLog ile aynı etkiye sahip olmak için yapılandırma kodu

[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];

2

Güvenlik açısından, neyin günlüğe kaydedildiğine bağlıdır. Eğer NSLog(ya da diğer kaydedicileri) hassas bilgileri yazıyor, o zaman üretim kodunda logger kaldırmalısınız.

Denetçi bakış açısından, denetçi NSLoghassas bilgilerin günlüğe kaydedilmediğinden emin olmak için her kullanımına bakmak istemez . Sadece kaydediciyi çıkarmanızı söyleyecektir.

Her iki grupla da çalışıyorum. Kodu denetleriz, kodlama kılavuzlarını yazarız vb. Kılavuzumuz, üretim kodunda günlüğe kaydetmenin devre dışı bırakılmasını gerektirir. Yani iç ekipler denememeyi biliyor;)

Yanlışlıkla sızan hassas bilgilerle ilgili riski kabul etmek istemediğimiz için üretimde oturum açan harici bir uygulamayı da reddedeceğiz. Geliştiricinin bize ne söylediğini umursamıyoruz. Sadece araştırmak için zaman ayırmaya değmez.

Ve unutmayın, geliştiriciyi değil, 'hassas' tanımlıyoruz;)

Ayrıca, günlüğe kaydedilmeye hazır bir uygulama olarak çok sayıda günlük kayıt gerçekleştiren bir uygulamayı da algılarım. Günlüğe kaydetmenin çok fazla yapılmasının / gerekli olmasının bir nedeni vardır ve genellikle istikrarı yoktur. Onun orada asılı hizmetleri yeniden başlatmak 'bekçi köpeği' konuları ile.

Hiç bir Güvenlik Mimarisi (SecArch) incelemesi gerçekleştirmediyseniz, bunlar baktığımız şeylerdir.


1

Sürüm kodunda printf veya NSLog ile gereksiz yere ayrıntılı olmamalısınız. Sadece uygulamanın kötü bir şey olması durumunda bir printf veya NSLog yapmayı deneyin, IE kurtarılamaz bir hata.


1

NSLogs'un UI / ana iş parçacığını yavaşlatabileceğini unutmayın. Kesinlikle gerekli olmadıkça onları sürüm yapılarından kaldırmak en iyisidir.


0

Günlük (Test) için TestFlight kullanmanızı şiddetle tavsiye ederim. Yöntemleri NSLog'u geçersiz kılar (bir makro kullanarak) ve mevcut NSLog çağrılarınız için sunucularına, Apple Sistem günlüğüne ve STDERR günlüğüne günlük kaydını açıp kapatmanıza olanak tanır. Bununla ilgili güzel olan şey, günlüklerin mesajlarını, kullanıcıların sistem günlüğünde görünmeyen günlükler olmadan, App Store'da dağıtılan uygulamalara ve uygulamalara dağıtılan uygulamalara yönelik olarak gözden geçirebilmenizdir. Her iki dünyanın en iyisi.


TestFlight'ın uygulamaya eklediği ek yükü dikkate almak gerekir. TestFlight öğesinin yalnızca günlük kaydı bölümünü eklemek mümkün müdür?
Johan Karlsson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.