2929
3030import org .telegram .messenger .time .FastDateFormat ;
3131import org .telegram .messenger .video .MediaCodecVideoConvertor ;
32+ import org .telegram .tgnet .NativeByteBuffer ;
3233import org .telegram .tgnet .TLObject ;
3334import org .telegram .tgnet .TLRPC ;
3435import org .telegram .ui .Components .AnimatedFileDrawable ;
4445import java .util .HashSet ;
4546import java .util .Locale ;
4647import java .util .Map ;
48+ import java .util .concurrent .atomic .AtomicInteger ;
4749
4850public class FileLog {
4951 private OutputStreamWriter streamWriter = null ;
@@ -88,91 +90,108 @@ private FileLog() {
8890
8991 private static Gson gson ;
9092 private static ExclusionStrategy exclusionStrategy ;
91- private static HashSet <String > excludeRequests ;
93+ // Dumps are best-effort diagnostics: never backpressure the network thread.
94+ private static final int MAX_PENDING_PROTOCOL_DUMPS = 8 ;
95+ private static final AtomicInteger pendingProtocolDumps = new AtomicInteger ();
96+
97+ private static void postProtocolDump (Runnable dump ) {
98+ if (pendingProtocolDumps .incrementAndGet () > MAX_PENDING_PROTOCOL_DUMPS ) {
99+ pendingProtocolDumps .decrementAndGet ();
100+ return ;
101+ }
102+ try {
103+ FileLog logger = getInstance ();
104+ if (logger .logQueue == null ) {
105+ pendingProtocolDumps .decrementAndGet ();
106+ return ;
107+ }
108+ logger .logQueue .postRunnable (() -> {
109+ try {
110+ dump .run ();
111+ } catch (Throwable e ) {
112+ // Application callbacks may have changed Java fields/collections
113+ // by now. A failed debug dump must not affect request processing.
114+ Log .e (tag , "Unable to serialize asynchronous protocol dump" , e );
115+ } finally {
116+ pendingProtocolDumps .decrementAndGet ();
117+ }
118+ });
119+ } catch (Throwable e ) {
120+ pendingProtocolDumps .decrementAndGet ();
121+ Log .e (tag , "Unable to queue protocol dump" , e );
122+ }
123+ }
92124
93125 public static void dumpResponseAndRequest (int account , TLObject request , TLObject response , TLRPC .TL_error error , long requestMsgId , long startRequestTimeInMillis , int requestToken ) {
94126 if (!BuildVars .DEBUG_PRIVATE_VERSION || !BuildVars .LOGS_ENABLED || request == null ) {
95127 return ;
96128 }
97129 String requestSimpleName = request .getClass ().getSimpleName ();
98- checkGson ();
99-
100- if (excludeRequests .contains (requestSimpleName ) && error == null ) {
130+ if (error == null && ("TL_upload_getFile" .equals (requestSimpleName ) || "TL_upload_getWebFile" .equals (requestSimpleName ))) {
101131 return ;
102132 }
103- try {
133+ long time = System .currentTimeMillis ();
134+ long requestingTime = time - startRequestTimeInMillis ;
135+ boolean hasError = error != null ;
136+ postProtocolDump (() -> {
137+ checkGson ();
104138 String req = "req -> " + requestSimpleName + " : " + gson .toJson (request );
105139 String res = "null" ;
106140 if (response != null ) {
107141 res = "res -> " + response .getClass ().getSimpleName () + " : " + gson .toJson (response );
108142 } else if (error != null ) {
109143 res = "err -> " + error .getClass ().getSimpleName () + " : " + gson .toJson (error );
110144 }
111- String finalRes = res ;
112- long time = System .currentTimeMillis ();
113- FileLog .getInstance ().logQueue .postRunnable (() -> {
114- try {
115- String metadata = "requestMsgId=" + requestMsgId + " requestingTime=" + (System .currentTimeMillis () - startRequestTimeInMillis ) + " request_token=" + requestToken + " account=" + account ;
116- FileLog .getInstance ().tlStreamWriter .write (getInstance ().dateFormat .format (time ) + " " + metadata );
117- FileLog .getInstance ().tlStreamWriter .write ("\n " );
118- FileLog .getInstance ().tlStreamWriter .write (req );
119- FileLog .getInstance ().tlStreamWriter .write ("\n " );
120- FileLog .getInstance ().tlStreamWriter .write (finalRes );
121- FileLog .getInstance ().tlStreamWriter .write ("\n \n " );
122- FileLog .getInstance ().tlStreamWriter .flush ();
123-
124- if (error != null ) {
125- Log .e (mtproto_tag , metadata );
126- Log .e (mtproto_tag , req );
127- Log .e (mtproto_tag , finalRes );
128- Log .e (mtproto_tag , " " );
129- } else {
130- Log .d (mtproto_tag , metadata );
131- Log .d (mtproto_tag , req );
132- Log .d (mtproto_tag , finalRes );
133- Log .d (mtproto_tag , " " );
134- }
135- } catch (Exception e ) {
136- e .printStackTrace ();
137- }
138- });
139- } catch (Throwable e ) {
140- FileLog .e (e , BuildVars .DEBUG_PRIVATE_VERSION );
141- }
145+ try {
146+ String metadata = "requestMsgId=" + requestMsgId + " requestingTime=" + requestingTime + " request_token=" + requestToken + " account=" + account ;
147+ FileLog logger = getInstance ();
148+ logger .tlStreamWriter .write (logger .dateFormat .format (time ) + " " + metadata );
149+ logger .tlStreamWriter .write ("\n " );
150+ logger .tlStreamWriter .write (req );
151+ logger .tlStreamWriter .write ("\n " );
152+ logger .tlStreamWriter .write (res );
153+ logger .tlStreamWriter .write ("\n \n " );
154+ logger .tlStreamWriter .flush ();
155+
156+ int priority = hasError ? Log .ERROR : Log .DEBUG ;
157+ Log .println (priority , mtproto_tag , metadata );
158+ Log .println (priority , mtproto_tag , req );
159+ Log .println (priority , mtproto_tag , res );
160+ Log .println (priority , mtproto_tag , " " );
161+ } catch (Exception e ) {
162+ e .printStackTrace ();
163+ }
164+ });
142165 }
143166
144167 public static void dumpUnparsedMessage (TLObject message , long messageId , int account ) {
145168 if (!BuildVars .DEBUG_PRIVATE_VERSION || !BuildVars .LOGS_ENABLED || message == null ) {
146169 return ;
147170 }
148- try {
171+ long time = System .currentTimeMillis ();
172+ boolean skipGson = gsonDisabled ;
173+ postProtocolDump (() -> {
149174 checkGson ();
150- getInstance ().dateFormat .format (System .currentTimeMillis ());
151- String messageStr = "receive message -> " + message .getClass ().getSimpleName () + " : " + (gsonDisabled ? message : gson .toJson (message ));
152- String res = "null" ;
153- long time = System .currentTimeMillis ();
154- FileLog .getInstance ().logQueue .postRunnable (() -> {
155- try {
156- String metadata = getInstance ().dateFormat .format (time ) + " msgId=" + messageId + " account=" + account ;
157-
158- FileLog .getInstance ().tlStreamWriter .write (metadata );
159- FileLog .getInstance ().tlStreamWriter .write ("\n " );
160- FileLog .getInstance ().tlStreamWriter .write (messageStr );
161- FileLog .getInstance ().tlStreamWriter .write ("\n \n " );
162- FileLog .getInstance ().tlStreamWriter .flush ();
163-
164- Log .d (mtproto_tag , "msgId=" + messageId + " account=" + account );
165- Log .d (mtproto_tag , messageStr );
166- Log .d (mtproto_tag , " " );
167- } catch (Exception e ) {
168- e .printStackTrace ();
169- }
170- });
171- } catch (Throwable e ) {
172- }
175+ String messageStr = "receive message -> " + message .getClass ().getSimpleName () + " : " + (skipGson ? message : gson .toJson (message ));
176+ try {
177+ FileLog logger = getInstance ();
178+ String metadata = logger .dateFormat .format (time ) + " msgId=" + messageId + " account=" + account ;
179+ logger .tlStreamWriter .write (metadata );
180+ logger .tlStreamWriter .write ("\n " );
181+ logger .tlStreamWriter .write (messageStr );
182+ logger .tlStreamWriter .write ("\n \n " );
183+ logger .tlStreamWriter .flush ();
184+
185+ Log .d (mtproto_tag , "msgId=" + messageId + " account=" + account );
186+ Log .d (mtproto_tag , messageStr );
187+ Log .d (mtproto_tag , " " );
188+ } catch (Exception e ) {
189+ e .printStackTrace ();
190+ }
191+ });
173192 }
174193
175- private static boolean gsonDisabled ;
194+ private static volatile boolean gsonDisabled ;
176195 public static void disableGson (boolean disable ) {
177196 gsonDisabled = disable ;
178197 }
@@ -202,11 +221,6 @@ private static void checkGson() {
202221 privateFields .add ("FLAG_" + i );
203222 }
204223
205- //exclude file loading
206- excludeRequests = new HashSet <>();
207- excludeRequests .add ("TL_upload_getFile" );
208- excludeRequests .add ("TL_upload_getWebFile" );
209-
210224 exclusionStrategy = new ExclusionStrategy () {
211225
212226 @ Override
@@ -219,7 +233,7 @@ public boolean shouldSkipField(FieldAttributes f) {
219233
220234 @ Override
221235 public boolean shouldSkipClass (Class <?> clazz ) {
222- return clazz .isInstance (DispatchQueue .class ) || clazz .isInstance (AnimatedFileDrawable .class ) || clazz .isInstance (ColorStateList .class ) || clazz .isInstance (Context .class );
236+ return NativeByteBuffer . class . isAssignableFrom ( clazz ) || clazz .isInstance (DispatchQueue .class ) || clazz .isInstance (AnimatedFileDrawable .class ) || clazz .isInstance (ColorStateList .class ) || clazz .isInstance (Context .class );
223237 }
224238 };
225239 gson = new GsonBuilder ()
@@ -278,6 +292,10 @@ public JsonElement serialize(TLObject src, Type typeOfSrc, JsonSerializationCont
278292 field .setAccessible (true );
279293 try {
280294 Object value = field .get (src );
295+ // Native buffers can already have been returned to their pool.
296+ if (value instanceof NativeByteBuffer ) {
297+ continue ;
298+ }
281299 if (value != null ) {
282300 Class clazz = value .getClass ();
283301 if (clazz .isInstance (DispatchQueue .class ) || clazz .isInstance (AnimatedFileDrawable .class ) || clazz .isInstance (ColorStateList .class ) || clazz .isInstance (Context .class )) {
0 commit comments